变更督程
督程行为支持更改内部状态,即,更改重启策略和最大重启频率属性,以及更改现存的子进程规格。
还可以添加和删除子进程,但这不是自动处理的。指令必须在 .appup 文件中给出。
变更属性
由于督程需要更改它的内部状态,所以必须使用同步代码替换。不过,必须使用特殊的 update 指令。
无论在升级还是降级的情况下,新版本的回调模块必须先加载。然后可以检查 init/1 的新返回值并相应改变内部状态。
对于督程要使用以下 upgrade 指令:
- {update, Module, supervisor}
例如:假设我们想将 Supervisor行为 一章中的 ch_sup 的重启策略从 one_for_one 更改成 one_for_all 。我们要修改 ch_sup.erl 中的回调函数 init/1 :
- -module(ch_sup).
- ...
- init(_Args) ->
- {ok, {{one_for_all, 1, 60}, ...}}.
文件 ch_app.appup :
- {"2",
- [{"1", [{update, ch_sup, supervisor}]}],
- [{"1", [{update, ch_sup, supervisor}]}]
- }.
变更子进程规格
当更改一个现存的子进程规格时,指令——包括 .appup 文件——和上述的变更属性是一样的:
- {"2",
- [{"1", [{update, ch_sup, supervisor}]}],
- [{"1", [{update, ch_sup, supervisor}]}]
- }.
更改不会影响现有的子进程。例如,更改了启动函数只会指定以后如果需要重启,那么子进程应该如何重启。
注意,子进程规格的id不可以被更改。
还要注意更改子进程规格的 Modules 字段可能会影响到发布处理过程自身,因为该字段用于在同步代码替换中识别哪些进程会受到影响。
添加和删除子进程
前面说过,变更子进程规格不会影响现存的子进程。新的子进程规格会被自动加入但不会被删除。并且,子进程不会自动启动或者终止,所以,必须明确使用 apply 指令。
例如:假设当 ch_app 从“1”升级到“2”时,我们想要给 ch_sup 添加一个新的子进程 m1 。这也意味着如果从“2”降级到“1”的时候, m1 要被删除。
- {"2",
- [{"1",
- [{update, ch_sup, supervisor},
- {apply, {supervisor, restart_child, [ch_sup, m1]}}
- ]}],
- [{"1",
- [{apply, {supervisor, terminate_child, [ch_sup, m1]}},
- {apply, {supervisor, delete_child, [ch_sup, m1]}},
- {update, ch_sup, supervisor}
- ]}]
- }.
注意指令的顺序非常重要。
还要注意督程必须注册为 ch_sup 该脚本才能正常运行。如果督程没有被注册,那它就不能直接从脚本中访问。这就必须写一个帮助函数用来找到督程的pid并调用 supervisor:restart_child 等,而且必须使用 apply 指令在脚本中调用该函数。
如果在 ch_app 的版本“2”中,引入了模块 m1 ,那么它也必须在升级时被加载,在降级时被删除:
- {"2",
- [{"1",
- [{add_module, m1},
- {update, ch_sup, supervisor},
- {apply, {supervisor, restart_child, [ch_sup, m1]}}
- ]}],
- [{"1",
- [{apply, {supervisor, terminate_child, [ch_sup, m1]}},
- {apply, {supervisor, delete_child, [ch_sup, m1]}},
- {update, ch_sup, supervisor},
- {delete_module, m1}
- ]}]
- }.
再次注意指令的顺序非常重要。当升级时,在可以启动新的子进程之前,必须加载 m1 并且更改督程的子进程规格。当降级时,子进程必须在更改子进程规格和删除模块之前终止。