我可以在不停止 运行 应用程序的情况下重新加载单个更改的 Erlang 模块吗?
Can I reload single changed Erlang module without stopping running application?
我的 Erlang 应用程序需要很长时间才能启动,甚至更长时间才能完全重新编译。我做了一些我想尽快测试的小改动。我想在不停止应用程序的情况下编译和加载我的更改。如何从启动应用程序后进入的 Erlang 控制台执行此操作?我的源代码位于 ./src
目录中,光束文件被编译到 ./ebin
目录中,我想对更改后的文件执行相同的操作。
我的应用程序以
开始
erl -pa ebin deps/*/ebin
像往常一样编译模块,然后将其输入 erlang shell:
l(my_module).
这将从新的 my_module.beam
文件加载代码并替换 my_module
模块。
旧版本可能不会完全消失 - 有关详细信息,请参阅 Erlang 参考手册中的 the section on Code Reloading。
您可以通过以下方式完成:
正在加载新版本的模块,例如c(module_name)
对新模块中的函数进行完全限定调用。 “完全合格”是指:
module_name:function_name()
模块仅在进行完全限定函数调用的过程中更新。
这是一个例子:
a.erl:
-module(a).
-compile(export_all).
start() ->
%% Long startup time:
timer:sleep(1000),
spawn(fun() -> loop() end).
loop() ->
receive
{a, Msg} ->
show1(Msg),
loop();
{b, Msg} ->
show2(Msg),
loop();
update_code -> a:loop()
end.
show1(Arg) ->
%%io:format("Hello ~w!~n", [Arg]). %original code
io:format("XXX ~w!~n", [Arg]). %new code
show2(Arg) ->
%%io:format("Goodbye ~w!~n", [Arg]). %original code
io:format("YYY ~w!~n", [Arg]). %new code
在shell:
1> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
2> Pid = a:start().
<0.72.0>
3> a:show1(jane). %%Executed by shell process.
Hello jane!
ok
4> Pid ! {a, jane}. %% show1/1 executed in spawned process.
Hello jane!
{a,jane}
5> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
6> a:show1(jane). %%Module updated in shell process.
XXX jane!
ok
7> Pid ! {a, jane}.
Hello jane! <---- STILL EXECUTING OLD MODULE
{a,jane}
8> Pid ! update_code. %% Make fully qualified function call in spawned process.
update_code
9> Pid ! {a, jane}. %% The whole module has been replaced by new code.
XXX jane!
{a,jane}
10> Pid ! {b, jane}.
YYY jane!
{b,jane}
11>
只是为了补充其他答案:
当您进行发布时,您可能有两个版本的应用程序并且您可能想要升级。比如说,您首先加载了 lib/foo-1.0.0/ebin/foo_app.beam
。然后你通过你喜欢的方法安装 foo-2.0.0
,我使用 target_system:install("foo", "/tmp/erl-target")
。现在我有 /tmp/erl-target/lib/foo-2.0.0/
.
我用code:which(foo_app)
看加载了哪一个。要加载它,在这种情况下,我将首先启动 Eshell:
$ /tmp/erl-target/bin/erl -boot /tmp/erl-target/releases/1/start
之后我输入:
1> application:ensure_all_started(foo).
{ok,[...,foo]}
要查看当前加载的是哪一个,您键入(在同一个 Eshell 中):
2> code:which(foo_app).
"/tmp/erl-target/lib/foo-1.0.0/ebin/foo_app.beam"
您将需要 /tmp/erl-target/lib/foo-2.0.0/ebin/
中的 foo.appup
文件,其中包含以下内容:
{"2.0.0",
[{"1.0.0",[{load_module,foo_app}]}],
[{"1.0.0",[{load_module,foo_app}]}]}.
要升级,您输入:
3> release_handler:upgrade_app(foo, 'lib/foo-2.0.0').
{ok,[]}
如果一切顺利,您将看到以下内容:
4> code:which(foo_app).
"/tmp/erl-target/lib/foo-2.0.0/ebin/foo_app.beam"
如果我在导出的 foo-2.0.0
中添加了一个新函数,它将可用,例如。
如果您想降级回以前的版本,您必须在 /tmp/erl-target/lib/foo-1.0.0/ebin/
中有一个类似的 foo.appup
文件,但交换了版本号。
如有错误请指正,我是Erlang新手。我自己测试过,它对我有用。这只是在一个版本中升级您的应用程序,而不是升级版本本身。
如果有什么不清楚的地方,请告诉我。我仍在尝试自己解决这个问题。 :)
我的 Erlang 应用程序需要很长时间才能启动,甚至更长时间才能完全重新编译。我做了一些我想尽快测试的小改动。我想在不停止应用程序的情况下编译和加载我的更改。如何从启动应用程序后进入的 Erlang 控制台执行此操作?我的源代码位于 ./src
目录中,光束文件被编译到 ./ebin
目录中,我想对更改后的文件执行相同的操作。
我的应用程序以
erl -pa ebin deps/*/ebin
像往常一样编译模块,然后将其输入 erlang shell:
l(my_module).
这将从新的 my_module.beam
文件加载代码并替换 my_module
模块。
旧版本可能不会完全消失 - 有关详细信息,请参阅 Erlang 参考手册中的 the section on Code Reloading。
您可以通过以下方式完成:
正在加载新版本的模块,例如
c(module_name)
对新模块中的函数进行完全限定调用。 “完全合格”是指:
module_name:function_name()
模块仅在进行完全限定函数调用的过程中更新。
这是一个例子:
a.erl:
-module(a).
-compile(export_all).
start() ->
%% Long startup time:
timer:sleep(1000),
spawn(fun() -> loop() end).
loop() ->
receive
{a, Msg} ->
show1(Msg),
loop();
{b, Msg} ->
show2(Msg),
loop();
update_code -> a:loop()
end.
show1(Arg) ->
%%io:format("Hello ~w!~n", [Arg]). %original code
io:format("XXX ~w!~n", [Arg]). %new code
show2(Arg) ->
%%io:format("Goodbye ~w!~n", [Arg]). %original code
io:format("YYY ~w!~n", [Arg]). %new code
在shell:
1> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
2> Pid = a:start().
<0.72.0>
3> a:show1(jane). %%Executed by shell process.
Hello jane!
ok
4> Pid ! {a, jane}. %% show1/1 executed in spawned process.
Hello jane!
{a,jane}
5> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
6> a:show1(jane). %%Module updated in shell process.
XXX jane!
ok
7> Pid ! {a, jane}.
Hello jane! <---- STILL EXECUTING OLD MODULE
{a,jane}
8> Pid ! update_code. %% Make fully qualified function call in spawned process.
update_code
9> Pid ! {a, jane}. %% The whole module has been replaced by new code.
XXX jane!
{a,jane}
10> Pid ! {b, jane}.
YYY jane!
{b,jane}
11>
只是为了补充其他答案:
当您进行发布时,您可能有两个版本的应用程序并且您可能想要升级。比如说,您首先加载了 lib/foo-1.0.0/ebin/foo_app.beam
。然后你通过你喜欢的方法安装 foo-2.0.0
,我使用 target_system:install("foo", "/tmp/erl-target")
。现在我有 /tmp/erl-target/lib/foo-2.0.0/
.
我用code:which(foo_app)
看加载了哪一个。要加载它,在这种情况下,我将首先启动 Eshell:
$ /tmp/erl-target/bin/erl -boot /tmp/erl-target/releases/1/start
之后我输入:
1> application:ensure_all_started(foo).
{ok,[...,foo]}
要查看当前加载的是哪一个,您键入(在同一个 Eshell 中):
2> code:which(foo_app).
"/tmp/erl-target/lib/foo-1.0.0/ebin/foo_app.beam"
您将需要 /tmp/erl-target/lib/foo-2.0.0/ebin/
中的 foo.appup
文件,其中包含以下内容:
{"2.0.0",
[{"1.0.0",[{load_module,foo_app}]}],
[{"1.0.0",[{load_module,foo_app}]}]}.
要升级,您输入:
3> release_handler:upgrade_app(foo, 'lib/foo-2.0.0').
{ok,[]}
如果一切顺利,您将看到以下内容:
4> code:which(foo_app).
"/tmp/erl-target/lib/foo-2.0.0/ebin/foo_app.beam"
如果我在导出的 foo-2.0.0
中添加了一个新函数,它将可用,例如。
如果您想降级回以前的版本,您必须在 /tmp/erl-target/lib/foo-1.0.0/ebin/
中有一个类似的 foo.appup
文件,但交换了版本号。
如有错误请指正,我是Erlang新手。我自己测试过,它对我有用。这只是在一个版本中升级您的应用程序,而不是升级版本本身。
如果有什么不清楚的地方,请告诉我。我仍在尝试自己解决这个问题。 :)