.appup
applicaiton upgrade files 可支援系統動態更新,裡面描述如何 upgrade/downgrade a running system,這個檔案會被 systools 的 relup 使用,產生 release upgrade file
application.appup
applicaiton.appup 必須要出現在 application 的 ebin
目錄
該檔案內容只包含一個 erlang term,定義 upgrade/downgrade application 的動作
{Vsn,
[{UpFromVsn, Instructions}, ...],
[{DownToVsn, Instructions}, ...]}.
% 目前 application version
Vsn = string()
% 更新自哪一版 application version
UpFromVsn = string() | binary()
% 降版時,要降成哪一個 application version
% 可使用 binary regex
% 例如 <<"2\\.1\\.[0-9]+">> 就是 2.1.*
DownToVsn = string() | binary()
% release upgrade instructions
Instructions
Release Upgrade Instructions
分為 high-level/low-level instructions,建議使用 high-level,systool 會自動產生 low-level instructions
high-level instructions
{update, Mod}
{update, Mod, supervisor}
{update, Mod, Change}
{update, Mod, DepMods}
{update, Mod, Change, DepMods}
{update, Mod, Change, PrePurge, PostPurge, DepMods}
{update, Mod, Timeout, Change, PrePurge, PostPurge, DepMods}
{update, Mod, ModType, Timeout, Change, PrePurge, PostPurge, DepMods}
Mod = atom()
ModType = static | dynamic
Timeout = int()>0 | default | infinity
Change = soft | {advanced,Extra}
Extra = term()
PrePurge = PostPurge = soft_purge | brutal_purge
DepMods = [Mod]
所有 processes 都會被 sys:suspend
暫停,載入新版 module 後,以 sys:resume
繼續執行
Change
預設為
soft
,定義 type of code change設定為
{advanced, Extra}
時,以gen_server
,gen_fsm
,gen_statem
,gen_event
時做的 processes,會呼叫code_change
改變內部狀態, Extra 為參數PrePurge
預設為
brutal_purge
載入新版 code 以前,控制執行舊版 code 的 processes 的動作
brutal_purge
就是把 process killedsoft_purge
,release_handler:install_release/1 returns {error,{old_processes,Mod}}.PostPurge
預設為
brutal_purge
載入新版 code 時,控制執行舊版 code 的 processes 的動作
brutal_purge
,當 release 確認永久生效時,code 被 purged,process 被 killedsoft_purge
,在沒有 process 執行舊版的 code 時,release handler 會 purges old codeDepMods
預設為
[]
定義 Mod 跟哪些 modules 相依
在 upgrading/downgrading 時,DepMods 的 processes,會被 suspended
Timeout
定義 suspending processes 的 timeout 時間
ModType
預設為
dynamic
dynamic
表示 process 會自動使用新版的 codestatic
,process 被詢問是否要 change code 以前,就會載入新版 code
supervisor 的 update,是用來修改 start spec
- 更新 module Mod
{load_module, Mod}
{load_module, Mod, DepMods}
{load_module, Mod, PrePurge, PostPurge, DepMods}
Mod = atom()
PrePurge = PostPurge = soft_purge | brutal_purge
DepMods = [Mod]
- 載入新的 module Mod
{add_module, Mod}
{add_module, Mod, DepMods}
Mod = atom()
DepMods = [Mod]
- 刪除 module
{delete_module, Mod}
{delete_module, Mod, DepMods}
Mod = atom()
- 新增 application
{add_application, Application}
{add_application, Application, Type}
Application = atom()
Type = permanent | transient | temporary | load | none
- 刪除 application
{remove_application, Application}
Application = atom()
- restart application
{restart_application, Application}
Application = atom()
example
{“0.2.0”,
[{“0.1.0”, [
{add_module, state_handler}
,{update, nine9s_sup, supervisor}
,{apply, {supervisor, restart_child, [nine9s_sup, state_handler]}}
,{load_module, default_handler}
,{add_module, count_handler}
,{load_module, nine9s_app}
,{apply, {nine9s_app, set_routes_new, [] }} ] }],
[{“0.1.0”, [
{load_module, default_handler}
,{apply, {supervisor, terminate_child, [nine9s_sup, state_handler]}}
,{apply, {supervisor, delete_child, [nine9s_sup, state_handler]}}
,{update, nine9s_sup, supervisor}
,{delete_module, state_handler}
,{apply, {nine9s_app, set_routes_old, [] }}
,{delete_module, count_handler}
,{load_module, nine9s_app}
]
}]}.
upgrade
- {add_module, state_handler}
- 增加 state_handler module
- {update, nine9s, supervisor}
- 修改 nine9s supervisor 內部狀態 及 spec
- {apply, {supervisor, restart_child, [nine9s, state_handler]}}
- apply 會執行
M:F(A1, … An)
- 也就是執行
supervisor:restart_child(nine9s, state_handler)
- apply 會執行
- {load_module, default_handler}
- 載入 default_handler module,取代舊版的 code
- {add_module, count_handler}
- 增加 count_handler module
- {load_module, nine9s_app}
- 載入 nine9s_app module
- {apply, {nine9s_app, set_routes_new, [ ] }} ] } ]
- 執行
nine9s_app:set_routes_new()
- 執行
downgrade
- {load_module, default_handler}
- 載入舊版的 default_handler
- {apply, {supervisor, terminate_child, [nine9s_sup, state_handler]}}
- 停止 state_handler process
- {apply, {supervisor, delete_child, [nine9s_sup, state_handler]}}
- 由
nine9s_sup
裡面刪除state_handler
- 由
- {update, nine9s_sup, supervisor}
- 修改 nine9s_sup 的內部狀態
- {delete_module, state_handler}
- 删除 state_handler module
- {apply, {nine9s_app, set_routes_old, [ ] }}
- 設定舊版的 routes
- {delete_module, count_handler}
- 刪除 count_handler module
- {load_module, nine9s_app}
- 載入舊版的 nine9s_app module
example of appup
- 更新 functional module
一般功能性的 module 修改後,都可以直接更新
{"2",
[{"1", [{load_module, m}]}],
[{"1", [{load_module, m}]}]
}.
- 修改常駐 module
除了 system processes, special processes 以外,常駐 module 就是supervisor, gens_server, gen_fsm, gen_statem, gen_event 其中之一。
- 修改 callback module
跟一般功能性的 module 修改一樣
{"2",
[{"1", [{load_module, ch3}]}],
[{"1", [{load_module, ch3}]}]
}.
- 修改 internal state
process 需要呼叫 code_change
{"2",
[{"1", [{update, ch3, {advanced, []}}]}],
[{"1", [{update, ch3, {advanced, []}}]}]
}.
-module(ch3).
...
-export([code_change/3]).
...
% downgrade 時呼叫
code_change({down, _Vsn}, {Chs, N}, _Extra) ->
{ok, Chs};
% upgrade 時呼叫
code_change(_Vsn, Chs, _Extra) ->
{ok, {Chs, 0}}.
- module dependencies
{load_module, Module, DepMods}
{update, Module, {advanced, Extra}, DepMods}
m1 跟 ch3 相依
myapp.appup:
{"2",
[{"1", [{load_module, m1, [ch3]}]}],
[{"1", [{load_module, m1, [ch3]}]}]
}.
ch_app.appup:
{"2",
[{"1", [{load_module, ch3}]}],
[{"1", [{load_module, ch3}]}]
}.
{"2",
[{"1",
[{load_module, ch3},
{load_module, m1, [ch3]}]}],
[{"1",
[{load_module, ch3},
{load_module, m1, [ch3]}]}]
}.
- 修改 special process 的 code
ch4 in proc_lib 由 supervisor 啟動, child spec 為
{ch4, {ch4, start_link, []},
permanent, brutal_kill, worker, [ch4]}
ch4 是 sp_app 的其中一個 application,在更新 1-> 2 時,必須要載入新版的 module
{"2",
[{"1", [{update, ch4, {advanced, []}}]}],
[{"1", [{update, ch4, {advanced, []}}]}]
}.
-module(ch4).
...
-export([system_code_change/4]).
...
system_code_change(Chs, _Module, _OldVsn, _Extra) ->
{ok, Chs}.
- 更新 supervisor
可修改 restart strategy 與 maximum restart frequency property
{update, Module, supervisor}
{"2",
[{"1", [{update, ch_sup, supervisor}]}],
[{"1", [{update, ch_sup, supervisor}]}]
}.
修改 child spec
{"2",
[{"1", [{update, ch_sup, supervisor}]}],
[{"1", [{update, ch_sup, supervisor}]}]
}.
add/delete child processes
{"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}
]}]
}.
{"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}
]}]
}.
- add/delete module
{"2",
[{"1", [{add_module, m}]}],
[{"1", [{delete_module, m}]}]
start/terminate a process
add/remove application
restart application
{"2",
[{"1", [{restart_application, ch_app}]}],
[{"1", [{restart_application, ch_app}]}]
}.
- 修改 application spec
{"2",
[{"1", []}],
[{"1", []}]
}.
- 修改 application configuration
也就是更新 sys.config
修改 included applications
修改 non-erlang code
emulator restart and upgrade
{"B",
[{"A",
[],
[restart_emulator]}],
[{"A",
[],
[restart_emulator]}]
}.
沒有留言:
張貼留言