Elixir 改代码后节点间函数调用会失败
Elixir's inter-node function call will fail after changing code
我正在像这样测试节点间函数调用 (rpc):
defmodule RpcTest do
def run do
Task.Supervisor.async( {DBServer.DistSupervisor, :'dbserver@hostname'}, fn -> "test" end)
|> Task.await
|> IO.inspect
end
end
然后我运行dbserver
节点,在dbserver
调用Task.Supervisor.start_link(name: DBServer.DistSupervisor)
接收rcp,在另一个节点dbclient
执行上面的代码
可以 运行 rpc 正确如下。
dbserver
$ iex --sname dbserver --cookie a -S mix
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Compiling 1 file (.ex)
Interactive Elixir (1.3.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(dbserver@hostname)1> Task.Supervisor.start_link(name: DBServer.DistSupervisor)
{:ok, #PID<0.101.0>}
iex(dbserver@hostname)2>
dbclient
$ elixir --sname dbclient --cookie a -S mix run -e RpcTest.run
"test"
但是,在我将代码从 "test"
更改为 "test test
" 之后,dbclient 节点不起作用。
这是错误信息
dbserver
iex(dbserver@hostname)2>
12:54:57.430 [error] Task #PID<0.110.0> started from {:"dbclient@hostname", #PID<13423.52.0>} terminating
** (BadFunctionError) expected a function, got: #Function<0.113878361/0 in RpcTest>
:erlang.apply/2
(elixir) lib/task/supervised.ex:94: Task.Supervised.do_apply/2
(elixir) lib/task/supervised.ex:45: Task.Supervised.reply/5
(stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Function: #Function<0.113878361/0 in RpcTest>
Args: []
dbclient
$ elixir --sname dbclient --cookie a -S mix run -e RpcTest.run
Compiling 1 file (.ex)
** (EXIT from #PID<0.52.0>) an exception was raised:
** (BadFunctionError) expected a function, got: #Function<0.113878361/0 in RpcTest.run/0>
:erlang.apply/2
(elixir) lib/task/supervised.ex:94: Task.Supervised.do_apply/2
(elixir) lib/task/supervised.ex:45: Task.Supervised.reply/5
(stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
此外,它 在 dbserver
手动重启后工作。
有趣的是,无论代码是什么,它 都可以与 iex
一起工作。
$ iex --sname dbclient --cookie a -S mix
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Compiling 1 file (.ex)
Interactive Elixir (1.3.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(dbclient@hostname)1> Task.Supervisor.async( {DBServer.DistSupervisor, :'dbserver@hostname'}, fn -> "test" end) |>
...(dbclient@hostname)1> Task.await |>
...(dbclient@hostname)1> IO.inspect
"test"
"test"
iex(dbclient@hostname)2> Task.Supervisor.async( {DBServer.DistSupervisor, :'dbserver@hostname'}, fn -> "test test" end) |>
...(dbclient@hostname)2> Task.await |>
...(dbclient@hostname)2> IO.inspect
"test test"
"test test"
我的问题是,
- 从另一个节点调用一个节点中的函数是不是方法不对?
- 使用节点间函数调用时,是否每次更改客户端代码都必须重新执行callee节点?
- 为什么
iex
和 elixir script
之间的行为不同?
代码和整个项目上传到这里:https://github.com/ayamamori/rpc_test/blob/master/lib/rpc_test.ex
提前致谢!
在 IEx 中声明的函数与在模块中声明的函数之间存在细微差别,即使它们是匿名的。
假设我们有以下模块:
defmodule FunInfo do
def info do
:erlang.fun_info(fn -> "test" end)
end
end
现在在 IEx 中:
iex(1)> FunInfo.info
[pid: #PID<0.91.0>, module: FunInfo, new_index: 0,
new_uniq: <<98, 250, 216, 183, 54, 136, 109, 221, 200, 243, 9, 84, 249, 185, 187, 173>>,
index: 0, uniq: 51893957, name: :"-info/0-fun-0-", arity: 0, env: [],
type: :local]
和相同的函数,但在 IEx 中声明:
iex(2)> :erlang.fun_info(fn -> "test" end)
[pid: #PID<0.91.0>, module: :erl_eval, new_index: 20,
new_uniq: <<103, 57, 49, 11, 11, 201, 159, 65, 226, 96, 121, 97, 18, 82, 151, 208>>,
index: 20, uniq: 54118792, name: :"-expr/5-fun-3-", arity: 0,
env: [{[], :none, :none,
[{:clause, 12, [], [],
[{:bin, 0,
[{:bin_element, 0, {:string, 0, 'test'}, :default, :default}]}]}]}],
type: :local]
我们可以强调一些关于函数信息的事情。对于 FunInfo
模块中定义的那个,我们有:
module: FunInfo
:new_uniq:
和 :uniq
标识符。
:env
不包含函数的 AST。
而对于 IEx 中的定义,我们有:
module: :erl_eval
:new_uniq:
和 :uniq
标识符。
:env
有匿名函数的 AST。
模块中声明的匿名函数
每次更改匿名函数源代码时,:new_uniq
和 :uniq
值都会更改。如果两个节点具有相同模块的不同版本,则此匿名函数将具有不同的 :new_uniq
和 :uniq
标识符。当你尝试执行服务器不知道的匿名函数时,它会失败。
IEx 中声明的匿名函数
:new_uniq
和 :uniq
值不会因您声明的每个函数而改变。它们位于已编译的 :erl_eval
模块中,您不会更改其源代码。此外,在 IEx 中声明的每个函数在 :env
中都有其 AST,因此当您要求远程节点执行该函数时,您也在发送函数的主体。
iex(1)> :erlang.fun_info(fn -> "test" end)
[pid: #PID<0.91.0>, module: :erl_eval, new_index: 20,
new_uniq: <<103, 57, 49, 11, 11, 201, 159, 65, 226, 96, 121, 97, 18, 82, 151, 208>>,
index: 20, uniq: 54118792, name: :"-expr/5-fun-3-", arity: 0,
env: [{[], :none, :none,
[{:clause, 26, [], [],
[{:bin, 0,
[{:bin_element, 0, {:string, 0, 'test'}, :default, :default}]}]}]}],
type: :local]
如果我创建另一个匿名函数,:new_uniq
和 :uniq
值不会改变,但 :env
值会随着正确的 AST 而改变。
iex(2)> :erlang.fun_info(fn -> "test test" end)
[pid: #PID<0.91.0>, module: :erl_eval, new_index: 20,
new_uniq: <<103, 57, 49, 11, 11, 201, 159, 65, 226, 96, 121, 97, 18, 82, 151, 208>>,
index: 20, uniq: 54118792, name: :"-expr/5-fun-3-", arity: 0,
env: [{[], :none, :none,
[{:clause, 27, [], [],
[{:bin, 0,
[{:bin_element, 0, {:string, 0, 'test test'}, :default, :default}]}]}]}],
type: :local]
我希望这能回答你的问题。
我正在像这样测试节点间函数调用 (rpc):
defmodule RpcTest do
def run do
Task.Supervisor.async( {DBServer.DistSupervisor, :'dbserver@hostname'}, fn -> "test" end)
|> Task.await
|> IO.inspect
end
end
然后我运行dbserver
节点,在dbserver
调用Task.Supervisor.start_link(name: DBServer.DistSupervisor)
接收rcp,在另一个节点dbclient
执行上面的代码
可以 运行 rpc 正确如下。
dbserver
$ iex --sname dbserver --cookie a -S mix
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Compiling 1 file (.ex)
Interactive Elixir (1.3.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(dbserver@hostname)1> Task.Supervisor.start_link(name: DBServer.DistSupervisor)
{:ok, #PID<0.101.0>}
iex(dbserver@hostname)2>
dbclient
$ elixir --sname dbclient --cookie a -S mix run -e RpcTest.run
"test"
但是,在我将代码从 "test"
更改为 "test test
" 之后,dbclient 节点不起作用。
这是错误信息
dbserver
iex(dbserver@hostname)2>
12:54:57.430 [error] Task #PID<0.110.0> started from {:"dbclient@hostname", #PID<13423.52.0>} terminating
** (BadFunctionError) expected a function, got: #Function<0.113878361/0 in RpcTest>
:erlang.apply/2
(elixir) lib/task/supervised.ex:94: Task.Supervised.do_apply/2
(elixir) lib/task/supervised.ex:45: Task.Supervised.reply/5
(stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Function: #Function<0.113878361/0 in RpcTest>
Args: []
dbclient
$ elixir --sname dbclient --cookie a -S mix run -e RpcTest.run
Compiling 1 file (.ex)
** (EXIT from #PID<0.52.0>) an exception was raised:
** (BadFunctionError) expected a function, got: #Function<0.113878361/0 in RpcTest.run/0>
:erlang.apply/2
(elixir) lib/task/supervised.ex:94: Task.Supervised.do_apply/2
(elixir) lib/task/supervised.ex:45: Task.Supervised.reply/5
(stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
此外,它 在 dbserver
手动重启后工作。
有趣的是,无论代码是什么,它 都可以与 iex
一起工作。
$ iex --sname dbclient --cookie a -S mix
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Compiling 1 file (.ex)
Interactive Elixir (1.3.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(dbclient@hostname)1> Task.Supervisor.async( {DBServer.DistSupervisor, :'dbserver@hostname'}, fn -> "test" end) |>
...(dbclient@hostname)1> Task.await |>
...(dbclient@hostname)1> IO.inspect
"test"
"test"
iex(dbclient@hostname)2> Task.Supervisor.async( {DBServer.DistSupervisor, :'dbserver@hostname'}, fn -> "test test" end) |>
...(dbclient@hostname)2> Task.await |>
...(dbclient@hostname)2> IO.inspect
"test test"
"test test"
我的问题是,
- 从另一个节点调用一个节点中的函数是不是方法不对?
- 使用节点间函数调用时,是否每次更改客户端代码都必须重新执行callee节点?
- 为什么
iex
和elixir script
之间的行为不同?
代码和整个项目上传到这里:https://github.com/ayamamori/rpc_test/blob/master/lib/rpc_test.ex
提前致谢!
在 IEx 中声明的函数与在模块中声明的函数之间存在细微差别,即使它们是匿名的。
假设我们有以下模块:
defmodule FunInfo do
def info do
:erlang.fun_info(fn -> "test" end)
end
end
现在在 IEx 中:
iex(1)> FunInfo.info
[pid: #PID<0.91.0>, module: FunInfo, new_index: 0,
new_uniq: <<98, 250, 216, 183, 54, 136, 109, 221, 200, 243, 9, 84, 249, 185, 187, 173>>,
index: 0, uniq: 51893957, name: :"-info/0-fun-0-", arity: 0, env: [],
type: :local]
和相同的函数,但在 IEx 中声明:
iex(2)> :erlang.fun_info(fn -> "test" end)
[pid: #PID<0.91.0>, module: :erl_eval, new_index: 20,
new_uniq: <<103, 57, 49, 11, 11, 201, 159, 65, 226, 96, 121, 97, 18, 82, 151, 208>>,
index: 20, uniq: 54118792, name: :"-expr/5-fun-3-", arity: 0,
env: [{[], :none, :none,
[{:clause, 12, [], [],
[{:bin, 0,
[{:bin_element, 0, {:string, 0, 'test'}, :default, :default}]}]}]}],
type: :local]
我们可以强调一些关于函数信息的事情。对于 FunInfo
模块中定义的那个,我们有:
module: FunInfo
:new_uniq:
和:uniq
标识符。:env
不包含函数的 AST。
而对于 IEx 中的定义,我们有:
module: :erl_eval
:new_uniq:
和:uniq
标识符。:env
有匿名函数的 AST。
模块中声明的匿名函数
每次更改匿名函数源代码时,:new_uniq
和 :uniq
值都会更改。如果两个节点具有相同模块的不同版本,则此匿名函数将具有不同的 :new_uniq
和 :uniq
标识符。当你尝试执行服务器不知道的匿名函数时,它会失败。
IEx 中声明的匿名函数
:new_uniq
和 :uniq
值不会因您声明的每个函数而改变。它们位于已编译的 :erl_eval
模块中,您不会更改其源代码。此外,在 IEx 中声明的每个函数在 :env
中都有其 AST,因此当您要求远程节点执行该函数时,您也在发送函数的主体。
iex(1)> :erlang.fun_info(fn -> "test" end)
[pid: #PID<0.91.0>, module: :erl_eval, new_index: 20,
new_uniq: <<103, 57, 49, 11, 11, 201, 159, 65, 226, 96, 121, 97, 18, 82, 151, 208>>,
index: 20, uniq: 54118792, name: :"-expr/5-fun-3-", arity: 0,
env: [{[], :none, :none,
[{:clause, 26, [], [],
[{:bin, 0,
[{:bin_element, 0, {:string, 0, 'test'}, :default, :default}]}]}]}],
type: :local]
如果我创建另一个匿名函数,:new_uniq
和 :uniq
值不会改变,但 :env
值会随着正确的 AST 而改变。
iex(2)> :erlang.fun_info(fn -> "test test" end)
[pid: #PID<0.91.0>, module: :erl_eval, new_index: 20,
new_uniq: <<103, 57, 49, 11, 11, 201, 159, 65, 226, 96, 121, 97, 18, 82, 151, 208>>,
index: 20, uniq: 54118792, name: :"-expr/5-fun-3-", arity: 0,
env: [{[], :none, :none,
[{:clause, 27, [], [],
[{:bin, 0,
[{:bin_element, 0, {:string, 0, 'test test'}, :default, :default}]}]}]}],
type: :local]
我希望这能回答你的问题。