简体   繁体   中英

erlang: failed to spawn(node, fun): badfun error

The remote node is located in the different machine.

I test from the local node:

$ erl -name foobar
Erlang/OTP 17 [erts-6.2] [source] [64-bit] [smp:2:2] [async-threads:10] [kernel-poll:false]

Eshell V6.2  (abort with ^G)
(foobar@debian.localdomain)1> Aliyun='aliyun@localhost2.localdomain'.
'aliyun@localhost2.localdomain'
(foobar@debian.localdomain)2> spawn(Aliyun, fun() -> io:format("hello~n") end).
<6108.86.0>
(foobar@debian.localdomain)3> 
=ERROR REPORT==== 4-Jul-2015::21:03:27 ===
Error in process <0.86.0> on node 'aliyun@localhost2.localdomain' with exit value: {{badfun,#Fun<erl_eval.20.90072148>},[{erlang,apply,2,[]}]}


(foobar@debian.localdomain)3> spawn(Aliyun, io, format, ["hello~n"]).          
hello
<6108.87.0>
(foobar@debian.localdomain)4> net_adm:ping(Aliyun).
pong

You could see that spawn(node,module,function,args) works, but the spawn(node,fun) does not.

The Erlang version on the remote node is R15, while the version on the local node is R17. Is it the reason? Because the code format is different? I'm not clear how Erlang marshal the fun type when passing it to the remote node. In bytecode?

Help please!

As the error message you received shows, the anonymous function is essentially treated in this context as if it were defined in the erl_eval module. If you have the same version of erl_eval on both the sending node and receiving node, everything works fine, since in that case both copies of erl_eval have the same version and checksums, so the receiving node is correctly able to evaluate an anonymous function passed from the sending node. But if the two nodes have different erl_eval modules, evaluating the anonymous function will fail.

An interesting thing to try is to define the anonymous function on the R15 node, convert it to a binary via term_to_binary/1 , send or copy the resulting binary over to the 17.x node, convert it back to a term via binary_to_term/1 , and then pass the resulting term as the anonymous function to your spawn call. First, on the R15 node:

(r15@myhost)1> F = fun() -> io:format("hello~n") end.
(r15@myhost)2> Bin = term_to_binary(F).
<<131,112,0,0,2,179,0,158,45,156,12,16,101,74,154,214,21,
  222,196,219,108,205,131,0,0,0,20,0,0,...>>
(r15@myhost)3> file:write_file("/tmp/fun", Bin).
ok

Now read the binary into the 17.x node, and make the spawn call with it back over to the R15 node:

(r17@myhost)1> {ok, Bin} = file:read_file("/tmp/fun").
{ok,<<131,112,0,0,2,179,0,158,45,156,12,16,101,74,154,
      214,21,222,196,219,108,205,131,0,0,0,20,...>>}
(r17@myhost)2> F = binary_to_term(Bin).
#Fun<erl_eval.20.82930912>
(r17@myhost)3> spawn(r15@myhost, F).
hello
<7101.90.0>

As you can see — and you should try it for yourself too — the spawn call works as expected because the anonymous function was created on the R15 node and it's also being evaluated there. The 17.x node merely passes it through.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM