变更被包含的应用

添加、删除、重启应用的发布处理指令只能作用于主应用。没有针对被包含的应用的相应指令。不过,由于一个被包含的应用其实就是一个有最高督程的监督树,并作为进行包含的应用中的某个督程的子进程被启动的,所以可以手工创建一个 relup 文件。

例如:假设我们有一个发布包含一个应用 prim_app ,它的监督树里有一个督程 prim_sup

在发布的新版本中,我们的范例应用 ch_app 要被包含在 prim_app 中。也就是说,它的最高督程要被作为 prim_sup 的子进程来启动。

  • 编辑 prim_sup 的代码:
  1. init(...) ->
  2. {ok, {...supervisor flags...,
  3. [...,
  4. {ch_sup, {ch_sup,start_link,[]},
  5. permanent,infinity,supervisor,[ch_sup]},
  6. ...]}}.
  • 编辑 prim_app 的 .app 文件:
  1. {application, prim_app,
  2. [...,
  3. {vsn, "2"},
  4. ...,
  5. {included_applications, [ch_app]},
  6. ...
  7. ]}.
  • 创建一个新的 .rel 文件,包含 ch_app :
  1. {release,
  2. ...,
  3. [...,
  4. {prim_app, "2"},
  5. {ch_app, "1"}]}.

应用重启

4.a. 一种启动被包含的应用的方式是重启整个 prim_app 应用。一般而言,我们要在 prim_app.appup 文件中使用 restart_application 指令。

但是,如果我们这么做并生成了 relup 文件,它不光会包含重启(即移除再添加) prim_app ,它还会包含启动 ch_app (在降级的情况下是停止)。这是由于 ch_app 也被包含在了新的 .rel 文件中,而旧的里面没有。

所以,正确的 relup 文件要被手工创建,要么重头写要么编辑生成好的版本。启动/停止 ch_app 的指令被替换成了加载/卸载应用的指令:

  1. {"B",
  2. [{"A",
  3. [],
  4. [{load_object_code,{ch_app,"1",[ch_sup,ch3]}},
  5. {load_object_code,{prim_app,"2",[prim_app,prim_sup]}},
  6. point_of_no_return,
  7. {apply,{application,stop,[prim_app]}},
  8. {remove,{prim_app,brutal_purge,brutal_purge}},
  9. {remove,{prim_sup,brutal_purge,brutal_purge}},
  10. {purge,[prim_app,prim_sup]},
  11. {load,{prim_app,brutal_purge,brutal_purge}},
  12. {load,{prim_sup,brutal_purge,brutal_purge}},
  13. {load,{ch_sup,brutal_purge,brutal_purge}},
  14. {load,{ch3,brutal_purge,brutal_purge}},
  15. {apply,{application,load,[ch_app]}},
  16. {apply,{application,start,[prim_app,permanent]}}]}],
  17. [{"A",
  18. [],
  19. [{load_object_code,{prim_app,"1",[prim_app,prim_sup]}},
  20. point_of_no_return,
  21. {apply,{application,stop,[prim_app]}},
  22. {apply,{application,unload,[ch_app]}},
  23. {remove,{ch_sup,brutal_purge,brutal_purge}},
  24. {remove,{ch3,brutal_purge,brutal_purge}},
  25. {purge,[ch_sup,ch3]},
  26. {remove,{prim_app,brutal_purge,brutal_purge}},
  27. {remove,{prim_sup,brutal_purge,brutal_purge}},
  28. {purge,[prim_app,prim_sup]},
  29. {load,{prim_app,brutal_purge,brutal_purge}},
  30. {load,{prim_sup,brutal_purge,brutal_purge}},
  31. {apply,{application,start,[prim_app,permanent]}}]}]
  32. }.

督程变更

4.b. 另一种方法是通过组合给 prim_sup 添加和删除子进程的指令和加载/卸载所有 ch_app 代码和应用规格的指令,来启动应用(在降级的情况下是停止)。

这次还是要手工创建 relup 文件。你重头写或者编辑生成的版本都可以。首先,在更新 prim_sup 之前,载入 ch_app 的所有代码并加载应用规格。当降级时, prim_sup 应该先被更新,在 ch_app 的代码和应用规格卸载之前。

  1. {"B",
  2. [{"A",
  3. [],
  4. [{load_object_code,{ch_app,"1",[ch_sup,ch3]}},
  5. {load_object_code,{prim_app,"2",[prim_sup]}},
  6. point_of_no_return,
  7. {load,{ch_sup,brutal_purge,brutal_purge}},
  8. {load,{ch3,brutal_purge,brutal_purge}},
  9. {apply,{application,load,[ch_app]}},
  10. {suspend,[prim_sup]},
  11. {load,{prim_sup,brutal_purge,brutal_purge}},
  12. {code_change,up,[{prim_sup,[]}]},
  13. {resume,[prim_sup]},
  14. {apply,{supervisor,restart_child,[prim_sup,ch_sup]}}]}],
  15. [{"A",
  16. [],
  17. [{load_object_code,{prim_app,"1",[prim_sup]}},
  18. point_of_no_return,
  19. {apply,{supervisor,terminate_child,[prim_sup,ch_sup]}},
  20. {apply,{supervisor,delete_child,[prim_sup,ch_sup]}},
  21. {suspend,[prim_sup]},
  22. {load,{prim_sup,brutal_purge,brutal_purge}},
  23. {code_change,down,[{prim_sup,[]}]},
  24. {resume,[prim_sup]},
  25. {remove,{ch_sup,brutal_purge,brutal_purge}},
  26. {remove,{ch3,brutal_purge,brutal_purge}},
  27. {purge,[ch_sup,ch3]},
  28. {apply,{application,unload,[ch_app]}}]}]
  29. }.