我可以在不停止运行应用程序的情况下重新加载单个更改的Erlang模块吗?

1rhkuytd  于 2022-12-08  发布在  Erlang
关注(0)|答案(3)|浏览(135)

我有一个Erlang应用程序,它需要很长的时间来启动,甚至更长的时间来完全重新编译。我做了一些小的更改,我想尽快测试。我想编译和加载我的更改,而不停止应用程序。如何从Erlang控制台,我得到后,启动应用程序?我的源代码位于./src目录下,束流文件被编译到./ebin目录下,我想对修改后的文件做同样的操作。

erl -pa ebin deps/*/ebin
ki1q1bka

ki1q1bka1#

You can do it by:

  1. Loading the new version of the module, e.g. c(module_name)
  2. Making a fully qualified call to a function in the new module. "Fully qualified" means:
module_name:function_name()

The module is only updated in the process where the fully qualified function call is made.
Here is an example:
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

In the 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>
xxe27gdn

xxe27gdn2#

Just to add to the other answers:
When you do a release, you may have two versions of your application and you may want to upgrade. Say, you first have lib/foo-1.0.0/ebin/foo_app.beam loaded. Then you install foo-2.0.0 via your preferred method, I use target_system:install("foo", "/tmp/erl-target") . Now I have /tmp/erl-target/lib/foo-2.0.0/ .
I use code:which(foo_app) to see which one is loaded. To load it, in this case I would first start the Eshell as such:

$ /tmp/erl-target/bin/erl -boot /tmp/erl-target/releases/1/start

Afterwards I type:

1> application:ensure_all_started(foo).
{ok,[...,foo]}

To see which one is currently loaded, you type (in the same Eshell):

2> code:which(foo_app).                                  
"/tmp/erl-target/lib/foo-1.0.0/ebin/foo_app.beam"

You will need the foo.appup file in /tmp/erl-target/lib/foo-2.0.0/ebin/ with the following contents:

{"2.0.0",
 [{"1.0.0",[{load_module,foo_app}]}],
 [{"1.0.0",[{load_module,foo_app}]}]}.

To upgrade, you type:

3> release_handler:upgrade_app(foo, 'lib/foo-2.0.0').
{ok,[]}

If everything was successful, you will see the following:

4> code:which(foo_app).                                  
"/tmp/erl-target/lib/foo-2.0.0/ebin/foo_app.beam"

If I added a new function in foo-2.0.0 which I exported, it will become available, for example.
If you want to downgrade back to the previous version, you will have to have a similar foo.appup file in /tmp/erl-target/lib/foo-1.0.0/ebin/ , but with the version numbers swapped.
Please correct me if I am wrong, I am new to Erlang. I did test it myself and it worked for me. This is just to upgrade your application within a release, this is not upgrading the release itself.
If something is unclear, let me know. I am still trying to work this out myself. :)

wxclj1h5

wxclj1h53#

像往常一样编译模块,然后在erlang shell中键入以下代码:

l(my_module).

这将从新的my_module.beam文件加载代码并替换my_module模块。
旧版本可能不会完全消失--有关详细信息,请参阅Erlang参考手册中的代码重新加载部分。

相关问题