下一个模块是一个超级基础的服务器,来说明没有OTP机制的代码更改。答案仅针对 erlang 代码。
-module (modtest).
-export ([init/0,loop/1]).
init() ->
spawn(?MODULE, loop, [version()]).
loop(Version) ->
receive
reload ->
io:format("external call state is ~p, current version is ~p~n",[Version,version()]),
?MODULE:loop(version());
stop ->
io:format("stopped~n");
Message ->
io:format("receive message ~p~n---> local call state is ~p, current version is ~p~n",[Message,Version,version()]),
loop(version())
after 10000 ->
io:format("timeout, state is ~p, current version is ~p~n",[Version,version()]),
loop(version())
end.
version() -> version1.
首先,尝试版本 1 中的模块
1> c(modtest).
{ok,modtest}
2> P = modtest:init().
<0.66.0>
timeout, state is version1, current version is version1
3> P! message1.
receive message message1
---> local call state is version1, current version is version1
message1
timeout, state is version1, current version is version1
4> P ! reload.
external call state is version1, current version is version1
reload
timeout, state is version1, current version is version1
接下来,进行一次巨大的进化
version() -> version2.
在 VM 外部编译模块并返回到正在运行的应用程序
5> % compile outside version 2
timeout, state is version1, current version is version1
5> P! message1.
receive message message1
---> local call state is version1, current version is version1
message1
6> P ! reload.
external call state is version1, current version is version1
reload
7> P! message1.
receive message message1
---> local call state is version1, current version is version1
message1
timeout, state is version1, current version is version1
什么都没发生,模块没有自动加载,让我们在VM中加载模块
8> % load new version
timeout, state is version1, current version is version1
8> l(modtest).
{module,modtest}
9> P! message1.
receive message message1
---> local call state is version1, current version is version1
message1
10> P ! reload.
external call state is version1, current version is version1
reload
11> P! message1.
receive message message1
---> local call state is version1, current version is version2
message1
12> P! message1.
receive message message1
---> local call state is version2, current version is version2
message1
timeout, state is version2, current version is version2
13> P! stop.
stopped
stop
14>
很好,新代码在模块中第一次“完全合格”调用后已更新,不幸的是,您无法控制何时考虑新代码。在示例中,即使有重新加载功能,新代码也会在下一个循环中使用,如果需要对状态数据进行任何修改,则为时已晚。下一个代码使用中间完全限定调用以允许修改状态数据。
-module (modtest).
-export ([init/0,loop/1,code_change/1]).
init() ->
spawn(?MODULE, loop, [version()]).
loop(Version) ->
receive
reload ->
NewVersion = ?MODULE:code_change(Version),
io:format("external call state is ~p, current version is ~p~n",[Version,NewVersion]),
?MODULE:loop(NewVersion);
stop ->
io:format("stopped~n");
Message ->
io:format("receive message ~p~n---> local call state is ~p, current version is ~p~n",[Message,Version,version()]),
loop(version())
after 10000 ->
io:format("timeout, state is ~p, current version is ~p~n",[Version,version()]),
loop(version())
end.
version() -> version3.
code_change(Version) ->
io:format("it is possible here to do any action on the state: ~p before the code change is completed~n",[Version]),
% It is possible to have different adaptation depending on the current version
version().
在虚拟机中检查这个新版本
1> c(modtest).
{ok,modtest}
2> P = modtest:init().
<0.66.0>
3> P ! message.
receive message message
---> local call state is version3, current version is version3
message
4> P ! message.
receive message message
---> local call state is version3, current version is version3
message
5> P ! reload.
it is possible here to do any action on the state: version3 before the code change is completed
reload
external call state is version3, current version is version3
6> P ! reload.
it is possible here to do any action on the state: version3 before the code change is completed
reload
external call state is version3, current version is version3
timeout, state is version3, current version is version3
7> % new version
做一个新版本
...
version() -> version4.
...
并返回虚拟机
7> c(modtest).
{ok,modtest}
timeout, state is version3, current version is version3
8> P ! message.
receive message message
---> local call state is version3, current version is version3
message
9> P ! message.
receive message message
---> local call state is version3, current version is version3
message
10> P ! reload.
it is possible here to do any action on the state: version3 before the code change is completed
reload
external call state is version3, current version is version4
11> P ! message.
receive message message
---> local call state is version4, current version is version4
message
12> P ! stop.
stopped
stop
13>
很好,它按预期工作。但是仍然有一个巨大的限制,“服务器”不能使用任何其他完全限定的调用,否则无法保证在加载新代码后立即调用函数 code_change。
这是 OTP 在版本升级或降级时带来的行为(参见release_handling )。