release_handler rebar hot code swap
Table of Contents
appup文件的格式
{Vsn, % Vsn 为当前version的appliction版本号
[{UpFromVsn1, InstructionsU1}, %UpFromVsn1 是前一版的版本号 ,InstructionsU1 是一个 指令 list
…,
{UpFromVsnK, InstructionsUK}],
[{DownToVsn1, InstructionsD1},
…,
{DownToVsnK, InstructionsDK}]}.
参考:
- https://bitbucket.org/basho/rebar/wiki/ReleaseHandling
- https://github.com/basho/rebar/wiki/Upgrades
- http://www.metabrew.com/article/erlangotp-releases-rebar-release_handler-appup-etc
- http://www.metabrew.com/article/erlang-rebar-tutorial-generating-releases-upgrades
- http://www.erlang.org/doc/design_principles/appup_cookbook.html#sup
- http://www.erlang.org/doc/design_principles/release_handling.html
- http://www.erlang.org/doc/system_principles/create_target.html
- http://www.erlang.org/doc/man/reltool.html
- http://stackoverflow.com/questions/7324556/cannot-start-sample-erlang-release-generated-with-rebar
操作步骤
cd release_handle/release_h/
make clean
cp src-0.1 src make
先使用0.1版的src进行编译
make createnode #这个make 指令其实执行如下命令 mkdir rel;cd rel;../rebar create-node nodeid=release_h
生成 ./rel目录,
不太明白为什么rebar起名字叫create-node
但是要想运行 rebar generate
./rel/目录下必须有rebar create-node nodeid=$(PROJECT) 命令生成的
一系列文件才行,比如 reltool.config
生成的reltool.config形如:
{sys, [ {lib_dirs, []}, {erts, [{mod_cond, derived}, {app_file, strip}]}, {app_file, strip}, {rel, "release_h", "1", [ kernel, stdlib, sasl, release_h ]}, {rel, "start_clean", "", [ kernel, stdlib ]}, {boot_rel, "release_h"}, {profile, embedded}, {incl_cond, exclude}, {excl_archive_filters, [".*"]}, %% Do not archive built libs {excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)", "^erts.*/(doc|info|include|lib|man|src)"]}, {excl_app_filters, ["\.gitignore"]}, {app, sasl, [{incl_cond, include}]}, {app, stdlib, [{incl_cond, include}]}, {app, kernel, [{incl_cond, include}]}, {app, release_h, [{incl_cond, include}]} ]}. {target_dir, "release_h"}. {overlay, [ {mkdir, "log/sasl"}, {copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"}, {copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"}, {copy, "files/release_h", "bin/release_h"}, {copy, "files/release_h.cmd", "bin/release_h.cmd"}, {copy, "files/start_erl.cmd", "bin/start_erl.cmd"}, {copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"}, {copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"}, {copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"} ]}.
这个生成的reltool.config有几处需要修改
- 注释掉这一行,{app_file, strip},
可能是rebar bug的原因,
我在 rebar generate-upgrade。。。 时,会报错,注释掉这句就可以了 - {lib_dirs, ["../.."]},
将本项目源码所在目录加到reltool.config的 lib_dirs中,这里使用了相对
目径,这样 reltool才能找到 本源目 - 修改版本号为0.1 {rel, "release_h", "0.1",…}
修改后的文件为
{sys, [ {lib_dirs, ["../.."]}, {erts, [{mod_cond, derived}, {app_file, strip}]}, %% {app_file, strip}, {rel, "release_h", "0.1", [ kernel, stdlib, sasl, release_h ]}, {rel, "start_clean", "", [ kernel, stdlib ]}, {boot_rel, "release_h"}, {profile, embedded}, {incl_cond, exclude}, {excl_archive_filters, [".*"]}, %% Do not archive built libs {excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)", "^erts.*/(doc|info|include|lib|man|src)"]}, {excl_app_filters, ["\.gitignore"]}, {app, sasl, [{incl_cond, include}]}, {app, stdlib, [{incl_cond, include}]}, {app, kernel, [{incl_cond, include}]}, {app, release_h, [{incl_cond, include}]} ]}. {target_dir, "release_h"}. {overlay, [ {mkdir, "log/sasl"}, {copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"}, {copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"}, {copy, "files/release_h", "bin/release_h"}, {copy, "files/release_h.cmd", "bin/release_h.cmd"}, {copy, "files/start_erl.cmd", "bin/start_erl.cmd"}, {copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"}, {copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"}, {copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"} ]}.
生成 ./rel/release_h
make generate #实际运行的是 ./rebar generate 可以查看下确保release_h-0.1被 打包到相应版本中 ls ./rel/release_h/lib/|grep release_h mv ./rel/release_h/ ./rel/release_h-0.1/
0.1版的release_h已经生成好了,适运行一下
cd ./rel/release_h/bin
./release_h console
Eshell V5.9.1 (abort with ^G) (release_h@jixiufeng-Joseph)1> hello_gen:hello(). 1 (release_h@jixiufeng-Joseph)2> hello_gen:module_info(attributes). [{vsn,"0.1"}] (release_h@jixiufeng-Joseph)3> (release_h@jixiufeng-Joseph)3> release_handler:which_releases(). [{"release_h","0.1", ["kernel-2.15.1","stdlib-1.18.1","sasl-2.2.1", "release_h-0.1"], permanent}] (release_h@jixiufeng-Joseph)4> tool:sayhello(). this is just a common module withou process running on ,so update this module is easy ok (release_h@jixiufeng-Joseph)5>
修改./rel/reltool.config
将版本号由0.1改成0.2
rm src cp src-0.2 src make clean make make generate ls rel/release_h/lib/|grep release_h make up ls rel/release_h/lib/release_h*/ebin |grep appup ls rel/|grep tar cp rel/release_h_0.2.tar.gz ./rel/release_h-0.1/releases/
用0.2版的代码生成新的 ./rel/release_h/
注意在0.2版的代码中 src/有 release_h.appup.src
编译过程中,会放到 ebin/release_h.appup
make up 命令执行两个命令
./rebar generate-appups previous_release=release_h-0.1 ./rebar generate-upgrade previous_release=release_h-0.1
关于参数previous_release后面跟 相对于./rel/目录的路径,比如,我将0.1版的
release_h目录命名为 release_h-0.1
generate-appups会在 ./rel/release_h/lib/release_h-0.2/ebin目录下生成
release_h.appup文件
如果 你的ebin/目录下没有appup文件的话, rebar 会为你生成一个,然后这它放到
./rel/release_h/lib/release_h-0.2/ebin目录中
generate-upgrade命令会在./rebar 生成一个tar.gz包
把release_h_0.2.tar.gz升级包 copy到 0.1版 的releases目录下 cp ./rel/release_h_0.2.tar.gz ./rel/release-0.1/releases/
在刚才测试0.1版的erlang shell中执行
erl> release_handler:unpack_release("release_h_0.2"). %解包 erl> release_handler:install_release("0.2"). % install erl> release_handler:make_permanent("0.2"). % 使0.2版成为默认版本
(release_h@jixiufeng-Joseph)2> release_handler:unpack_release("release_h_0.2"). {ok,"0.2"} (release_h@jixiufeng-Joseph)3> release_handler:install_release("0.2"). if you see this line ,that means hello_gen.erl is updated hello_gen update from version 0.1 and current version is 0.2 and the third param Extra is "Extra info for code_change/3" if you see this line that means world_gen is started {ok,"0.1",[]} (release_h@jixiufeng-Joseph)4> release_handler:make_permanent("0.2"). ok (release_h@jixiufeng-Joseph)5>
查看一下确认已经升级到0.2
(release_h@jixiufeng-Joseph)5> release_handler:which_releases(). [{"release_h","0.2", ["kernel-2.15.1","stdlib-1.18.1","sasl-2.2.1", "release_h-0.2"], current}, {"release_h","0.1", ["kernel-2.15.1","stdlib-1.18.1","sasl-2.2.1", "release_h-0.1"], permanent}] (release_h@jixiufeng-Joseph)7> whereis(world_gen). <0.60.0> (release_h@jixiufeng-Joseph)10> supervisor:which_children(hello_sup). [{world_gen,<0.60.0>,worker,[world_gen]}, {hello_gen,<0.49.0>,worker,[hello_gen]}] (release_h@jixiufeng-Joseph)11> (release_h@jixiufeng-Joseph)11> tool:sayworld(). this is just a common module withou process running on ,so update this module is easy