在Erlang'中实现代码交换;s gen_服务器

在Erlang'中实现代码交换;s gen_服务器,erlang,otp,hotswap,Erlang,Otp,Hotswap,我希望在gen_服务器上使用Erlang的热代码交换功能,这样就不必重新启动它。我该怎么做?当我搜索时,我只能找到一篇文章,其中提到我需要使用genu服务器:code\u changecallback 但是,我找不到任何关于如何使用此功能的文档/示例。非常感谢任何帮助或资源链接 您不需要在genu服务器行为中使用该回调。如果在代码升级过程中更改状态的内部表示形式,则会出现这种情况 您只需加载新模块,运行旧版本的gen_服务器将升级,因为它调用新模块。只是如果有必要,您没有机会更改表示方式。如果您

我希望在gen_服务器上使用Erlang的热代码交换功能,这样就不必重新启动它。我该怎么做?当我搜索时,我只能找到一篇文章,其中提到我需要使用
genu服务器:code\u change
callback


但是,我找不到任何关于如何使用此功能的文档/示例。非常感谢任何帮助或资源链接

您不需要在
genu服务器
行为中使用该回调。如果在代码升级过程中更改状态的内部表示形式,则会出现这种情况


您只需加载新模块,运行旧版本的
gen_服务器将升级,因为它调用新模块。只是如果有必要,您没有机会更改表示方式。

如果您希望以正确的方式进行更改,这是强烈建议的,那么您需要详细了解OTP监督员和应用程序的使用情况

您可能比在此处阅读OTP设计原则用户指南更糟糕:


最简单的方法是替换
.beam
文件,然后在shell中运行
l(我的服务器模块)。
。这绕过了
code\u change
功能,因此要求状态的表示形式没有改变


如前所述,正确的方法是使用appup和relup脚本创建一个新版本。然后安装此新版本。

正如我已经提到的,正常的升级方法是创建适当的.appup和.relup文件,并让release\u处理程序执行需要执行的操作。但是,您可以手动执行所涉及的步骤,如下所述。对不起,回答得太长了

以下虚拟gen_服务器实现一个计数器。旧版本(“0”)仅将整数存储为状态,而新版本(“1”)将{tschak,Int}存储为状态。正如我所说,这是一个虚假的例子

z、 erl(旧版):

z、 erl(新):

启动shell,编译旧代码。请注意,gen_服务器是通过调试跟踪启动的

1> c(z).
{ok,z}
2> z:start_link().
{ok,<0.38.0>}
3> z:boing().
*DBG* z got call boom from <0.31.0>
*DBG* z sent 0 to <0.31.0>, new state 1
0
4> z:boing().
*DBG* z got call boom from <0.31.0>
*DBG* z sent 1 to <0.31.0>, new state 2
1
你刚才做的:5:编译新代码。6:已挂起服务器。7:清除旧代码(以防万一)。8:加载新代码。9:在进程“z”中为模块“z”调用了代码更改,从版本“0”到[]作为“额外”传递到代码更改。10:恢复服务器

现在,如果您再运行一些测试,您可以看到服务器使用新的状态格式:

11> z:boing().
*DBG* z got call boom from <0.31.0>
*DBG* z sent 2 to <0.31.0>, new state {tschak,3}
2
12> z:boing().
*DBG* z got call boom from <0.31.0>
*DBG* z sent 3 to <0.31.0>, new state {tschak,4}
3
11>z:boing()。
*DBG*z收到了来自
*DBG*z将2发送到,新状态{tschak,3}
2.
12> z:boing()。
*DBG*z收到了来自
*DBG*z将3发送到,新状态{tschak,4}
3.

如果您在rebar3上,一些手动处理已经自动化(即appup和relup生成),您可以在此处找到更多信息:

当您指“加载新模块”时,您的意思是,我只是重新编译使用genserver的模块,运行中的服务器会自动升级自身吗?如果您从Erlang shell编译它(比如使用c()),就会发生这种情况。否则,请使用code:load_file/2或code:load_binary/2获得类似效果。如果您加载模块的新版本而不挂起gen_服务器进程,则下次运行回调时,它将使用新代码和旧状态运行。对回调模块的所有调用都是外部调用,因此始终使用最新加载的模块版本。因此需要暂停、加载、更改代码、恢复升级过程。没有魔法代码升级事件订阅正在进行。@Archelus Ugg。。。所以,如果我做到了这一点,如果我没有使用gen_server,那么我就不需要挂起,因为这样我就可以将所有调用保持在本地(除了?MODULE:code_change)。与“天真”的方式相比,这种gen_服务器代码更改似乎非常不酷:(是的-这种交互有点微妙,也不是真正的想法,但使用gen_服务器框架的好处远远超过了这一麻烦。我强烈建议使用gen_服务器并处理挂起、加载、更改代码和恢复周期。(只有在更改状态时才需要){}-如果不更改#state{},您可以直接加载。谢谢,我读过不同的OTP行为,我只是找不到与此相关的任何信息。在z.erl的版本1中,init应该返回{ok,{tschak,0}作为初始状态。如果虚拟机在加载后使用新版本,为什么还要调用
code:purge
?嗯。为什么sys:change\u代码要求进程停止?如果我刚刚在代码中的某个地方放了?MODULE:loop(而不是使用gen\u server),那就没有必要了。。。
1> c(z).
{ok,z}
2> z:start_link().
{ok,<0.38.0>}
3> z:boing().
*DBG* z got call boom from <0.31.0>
*DBG* z sent 0 to <0.31.0>, new state 1
0
4> z:boing().
*DBG* z got call boom from <0.31.0>
*DBG* z sent 1 to <0.31.0>, new state 2
1
5> compile:file(z).
{ok,z}
6> sys:suspend(z).
ok
7> code:purge(z).
false
8> code:load_file(z).
{module,z}
9> sys:change_code(z,z,"0",[]).
ok
10> sys:resume(z).
ok
11> z:boing().
*DBG* z got call boom from <0.31.0>
*DBG* z sent 2 to <0.31.0>, new state {tschak,3}
2
12> z:boing().
*DBG* z got call boom from <0.31.0>
*DBG* z sent 3 to <0.31.0>, new state {tschak,4}
3