1

I am writing Elixir to get record from remote nodes, I have write a module,

   defmodule Connect do
      def connect do
      node_ap_dev_ejd = :'abc@abc.com'
      :net_adm.ping(node_ap)

      fbUsersFun = fn(x) -> :binary.part(x,{0,3}) == <<"*ab">> end
      f = fn()-> :mnesia.dirty_select(:'cz_map',[{{:cz_map, :'$1', :'_',:'_',:'_'},[],[:'$1']}]) end

      fbUserList = :rpc.call(node_ap_dev_ejd,:mnesia,:activity,[:async_dirty,f])
      list = Enum.filter(fbUserList ,fbUsersFun)
      length(list)
      end
   end    

I can run the code if I put it in iex shell line by line, however if I compile the code and run Connect.connect , this error appear, I have no idea of it, please suggest

** (Protocol.UndefinedError) protocol Enumerable not implemented for 
{:badrpc, {:EXIT, {:undef, [{#Function<1.96315226/0 in Connect.connect/0>, [], []}, {:mnesia_tm, :non_transaction, 5, [file: 'mnesia_tm.erl', line: 738]}]}}}
(elixir) lib/enum.ex:1: Enumerable.impl_for!/1
(elixir) lib/enum.ex:112: Enumerable.reduce/3
(elixir) lib/enum.ex:666: Enum.filter/2
         second_function.ex:10: Connect.connect/0
want_to_be_calm
  • 1,477
  • 3
  • 23
  • 41

2 Answers2

2

It means that the Enumerable protocol is not implemented for the data {:badrpc, ...}.

Most likely, that error comes from this line:

list = Enum.filter(fbUserList ,fbUsersFun)

In that line, you're trying to filter fbUserList which I guess is {:badrpc, ...} instead of an enumerable. Tuples are not enumerables; lists and maps (and other things) are.

The solution probably lies in a case expression which checks the result returned by :rpc.call/4 in order to defend from errors:

case :rpc.call(node_ap_dev_ejd, :mnesia, :activity, [:async_dirty, f]) do
  {:badrpc, _} -> raise "bad rpc error"
  fbUserList   -> Enum.filter(fbUserList, ...) # and so on
end
whatyouhide
  • 15,897
  • 9
  • 57
  • 71
  • Hi, thanks your answer. I check the Elixir document, and found that Enum.filter will handle collections, which include the tuples. After using the case, I found the `:rpc.call(node_ap_dev_ejd, :mnesia, :activity, [:async_dirty, f])` always raise "bad rpc error". But strange, if I run the `"rpc.call(node_ap_dev_ejd, ...) in shell directly, it runs successfully. I don't know what makes the difference. – want_to_be_calm Apr 16 '15 at 15:01
  • @PeterHon `Enum.filter/2` **does not** handle collections, as the `Enumerable` protocol is not implemented for tuples. Try running `Enum.filter({1, 2}, fn(el) -> el > 1 end)` in IEx so you can verify for yourself :). – whatyouhide Apr 16 '15 at 16:19
  • thanks. But for the case statement , it will always raise error. I am wondering why the rpc.call works in iex but not in module. – want_to_be_calm Apr 16 '15 at 16:24
  • @PeterHon if I had to guess, I'd say some timing problem: calls in the shell happen "distant" from each other since it takes you time to type them, while the code being executed executes virtually with no delay. – whatyouhide Apr 16 '15 at 17:50
  • Thanks. Same guess. Maybe I need to put time sleep after rpc call. But I think the elixir should handle it properly. – want_to_be_calm Apr 17 '15 at 01:14
  • By the way, how can I assign a certain time for rpc call in Elixir? – want_to_be_calm Apr 17 '15 at 03:04
  • I tried to read the error message, `{:undef, [{#Function<1.96315226/0 in Connect.connect/0>, [], []}` , I dig in to mnesia_tm source code, I found the EXIT is triggered in non_transaction module, so what is the possible reason that triggered the function – want_to_be_calm Apr 17 '15 at 10:26
  • @PeterHon I'm sorry I never used mnesia so I won't be able to help here. As a suggestion, maybe ask a separate question about your problem with mnesia and tag it as an Erlang and mnesia question, you may find more help that way :). – whatyouhide Apr 17 '15 at 10:30
  • Thanks so much what youngish – want_to_be_calm Apr 17 '15 at 10:34
0

I'm having the same issue working mnesia with erlang, the error is because of the anonymous function "f", the thing is that the remote node does not recognize that function because it was created in another node.

EDIT:

I managed to solve the problem in erlang, I will show you how I did it in erlang, I don't know much about elixir but I´m sure if it can be done in erlang it will in elixir.

So this segment

 f = fn()-> :mnesia.dirty_select(:'cz_map',[{{:cz_map, :'$1', :'_',:'_',:'_'},[],[:'$1']}]) end

  fbUserList = :rpc.call(node_ap_dev_ejd,:mnesia,:activity,[:async_dirty,f])

In erlang is like this

f = fun()-> mnesia:dirty_select(cz_map,[{{cz_map, '$1', '_', '_', '_'},[],['$1']}]) end,
fbUserList = rpc:call(node_ap_dev_ejd, mnesia, activity, [async_dirty, f])

Instead declaring an anonymous fun you have to do something like this

fbUserList = rpc:call(node_ap_dev_ejd, mnesia, activity, [async_dirty, mnesia:dirty_select/2, [cz_map, [{{cz_map, '$1', '_', '_', '_'},[],['$1']}]]])

You can find a clear explanation here what kind of types can be sent on an erlang message?

I hope this information helps you.

Community
  • 1
  • 1
jasmad
  • 115
  • 9