发布处理指令

OTP支持一套发布处理指令(用在创建 .appup 文件的时候)。发布处理器可以理解该指令的一个子集——低级指令。为了让用户用得简单,还有一系列高级指令,可以通过 systools:make_relup 翻译为低级指令。

这里将解释一些最常用的指令。指令的完整列表可以在 appup(4) 中找到。

首先是一些定义:

  • 驻留模块
  • 该模块中有一个(或多个)属于某个进程的尾递归循环函数。如果尾递归循环函数是在多个模块中实现的,那么所有这些模块都是该进程的驻留模块。
  • 功能模块
  • 对任何进程都不是驻留模块的模块。注意对于使用了OTP行为实现的进程,行为模块是该进程的驻留模块。回调模块是功能模块。

load_module

如果对某个功能模块进行了简单的扩展,那么只要简单地将模块的新版本载入系统并删除就版本即可。这称之为简单代码替换,可以使用以下指令:

  1. {load_module, Module}

update

如果进行了更加复杂的更改,例如对某个gen_server的内部状态的格式进行了更改,那么简单代码替换就不够了。这时需要挂起使用该模块的进程(防止其在代码替换完成之前再处理任何请求),并让他们转换内部状态的格式,并切换到模块的新版本上,删除旧版本,最后恢复进程。这称之为同步代码替换,它要用到以下指令:

  1. {update, Module, {advanced, Extra}}
  2. {update, Module, supervisor}

当进行如上所述的变更行为的内部的状态时,要用到带有参数 {advanced,Extra}update 。它会让行为进程调用回掉函数 codechange ,并将值 Extra 和其他一些信息作为参数传递给它。参见相应行为的手册和 [_Appup Cookbook]($589893706c6c9562.md#appup-cookbook) 。

当更改督程的启动规格的时候,要用到带有 supervisor 参数的 update 。参见 Appup Cookbook

发布处理器通过遍历每个运行的应用的监督树并检查所有的子进程规格来查找使用某个模块的进程:

  1. {Id, StartFunc, Restart, Shutdown, Type, Modules}

如果某个模块的名字列在某个进程的子进程规格的 Modules 中,那么该进程在使用该模块。

如果 Modules=dynamic ,即事件管理器的情况,那么事件管理器进程会告知发布处理器目前安装了的事件处理器(gen_fsm),然后检查是否模块名在这个列表中。

发布处理器挂起进程、要求代码变更,并恢复进程是通过相应地调用 sys:suspend/1,2sys:change_code/4,5sys:resume/1,2 来完成的。

add_module 和 delete_module

如果引入了一个新的模块,可以使用以下代码:

  1. {add_module, Module}

该指令加载模块并在当Erlang运行于嵌入模式的时候是绝对必须的。当Erlang运行于交互模式(默认)时则并非严格要求,因为代码服务器会自动搜索并加载未加载的模块。

add_module 模块的对面就是 delete_module ,他用于卸载一个模块:

  1. {delete_module, Module}

注意在任何应用中的任何进程,当 Module 是驻留进程时,在运行指令的时候都会被杀死。因此用户必须确保在删除模块的时候所有这种进程必须终止,来避免出现督程失败重启的情况。

应用指令

添加一个应用的指令为:

  1. {add_application, Application}

添加一个应用表示由在 .app 文件中的 modules 键定义的模块已经使用了一系列 add_module 指令加载了,然后该应用被启动。

移除一个应用的指令为:

  1. {remove_application, Application}

移除一个应用表示该应用被停止,并使用一系列 delete_module 指令将模块都卸载,然后该应用规格从应用控制器中被卸载。

重启一个应用的指令为:

  1. {restart_application, Application}

重启一个应用表示该应用被停止,然后再启动,类似于先使用 remove_application 再使用 add_application

apply(低级)

要从发布处理器中调用任意函数,可以使用以下指令:

  1. {apply, {M, F, A}}

这样发布处理器会执行 apply(M,F,A)

restart_new_emulator(低级)

该指令用于当变更到一个新的模拟器版本上,或者由于某种其他原因需要进行系统重启。要求该系统必须启用了心跳监控,参见 erl(1)heart(3)

当发布处理器遇到该指令时,他通过调用 init:reboot() 关闭当前的模拟器,参见 init(3) 。所有的进程都被优雅地停止然后系统可以通过心脏程序重启,并使用新的发布版本。当新的模拟器版本启动并运行后,这个新的版本必须被设置为固定的。否则,如果系统又重启了则会使用旧的版本。

在UNIX上,发布处理器会告诉心脏程序使用哪个版本重启系统。注意环境变量 HEART_COMMAND ,通常由心脏程序使用,在这个案例中是被忽略的。这个命令默认是 $ROOT/bin/start 。还可以使用SASL配置参数 start_prg 来设置另一个命令,参见 sasl(6)