更新: | 2013-02-22 |
---|---|
バージョン: | 0.0.4 |
作者: | @voluntas |
URL: | http://voluntas.github.com/ |
一度もサーバは落としてません
https://github.com/voluntas/snowflake/tree/feature/webmachine
Erlang は動いたままで無停止でコードを変更する事が出来ると言われますが、実際に見たことがある人はほとんどいない気がしたので、ウェブの API をホットスワップして切り替えるというサンプルを書いてみることにしました。
流れは以下の通りです。
- 普通にデプロイして起動
- 戻している JSON の一部の名前が間違っていた
- ホットスワップでアップデートする。
rebar generate で rel 以下にリリースデータを生成します。
$ ./rebar compile ==> mochiweb (compile) ==> webmachine (compile) ==> rel (compile) ==> snowflake (compile) Compiled src/snowflake_wm_user.erl $ ./rebar generate ==> rel (generate) $ mv rel/snowflake rel/snowflake_1 $ ./rebar clean ==> mochiweb (clean) ==> webmachine (clean) ==> rel (clean) ==> snowflake (clean) $ ./rel/snowflake_1/bin/snowflake console Exec: /tmp/snowflake/rel/snowflake_1/erts-5.9.3/bin/erlexec -env ERL_LIBS /tmp/snowflake/rel/snowflake_1/lib -boot /tmp/snowflake/rel/snowflake_1/releases/1/snowflake -config /tmp/snowflake/rel/snowflake_1/releases/1/sys.config -args_file /tmp/snowflake/rel/snowflake_1/releases/1/vm.args -- console Root: /tmp/snowflake/rel/snowflake_1 Erlang R15B03 (erts-5.9.3) [source] [64-bit] [smp:4:4] [async-threads:0] [kernel-poll:false] [dtrace] ([email protected])1>
httpie で API を確認します
https://github.com/jkbr/httpie
ユーザが見つからない:
$ http GET localhost:8080/users/1234 HTTP/1.1 404 Object Not Found Content-Length: 193 Content-Type: text/html Date: Thu, 21 Feb 2013 06:10:20 GMT Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue) <HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY><H1>Not Found</H1>The requested document was not found on this server.<P><HR><ADDRESS>mochiweb+webmachine web server</ADDRESS></BODY></HTML>
ユーザ情報の追加:
$ http PUT localhost:8080/users/1234 password=pass -j HTTP/1.1 201 Created Content-Length: 36 Content-Type: application/json Date: Thu, 21 Feb 2013 06:10:25 GMT Location: /users/1234 Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue) { "password": "pass", "user_id": "1234" }
ユーザ情報の確認:
$ http GET localhost:8080/users/1234 HTTP/1.1 200 OK Content-Length: 36 Content-Type: application/json Date: Thu, 21 Feb 2013 06:10:27 GMT Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue) { "password": "pass", "user_id": "1234" }
JSON(というか JS 標準) の命名規則は userId のため、間違っています。 サーバを止めずにホットスワップで切り替えます。
変更点は以下の通りです
- バージョンを 1 から 2 へ上げる
- JSON 出力の user_id を userId にする
変更差分
$ git diff
diff --git a/rel/reltool.config b/rel/reltool.config
index b0b833f..a35c90b 100644
--- a/rel/reltool.config
+++ b/rel/reltool.config
@@ -2,7 +2,7 @@
{lib_dirs, ["../deps"]},
{erts, [{mod_cond, derived}, {app_file, strip}]},
{app_file, strip},
- {rel, "snowflake", "1",
+ {rel, "snowflake", "2",
[
kernel,
stdlib,
diff --git a/src/snowflake.app.src b/src/snowflake.app.src
index 08c788c..5294402 100644
--- a/src/snowflake.app.src
+++ b/src/snowflake.app.src
@@ -1,7 +1,7 @@
{application, snowflake,
[
{description, ""},
- {vsn, "1"},
+ {vsn, "2"},
{registered, []},
{applications, [
kernel,
diff --git a/src/snowflake_wm_user.erl b/src/snowflake_wm_user.erl
index ff8c8ec..6352940 100644
--- a/src/snowflake_wm_user.erl
+++ b/src/snowflake_wm_user.erl
@@ -54,7 +54,7 @@ delete_resource(RD, #ctx{user = User} = Ctx) ->
to_json(RD, #ctx{user = User} = Ctx) ->
- Result = mochijson2:encode({struct, [{<<"user_id">>, User#user.id},
+ Result = mochijson2:encode({struct, [{<<"userId">>, User#user.id},
{<<"password">>, User#user.password}]}),
{Result, RD, Ctx}.
@@ -65,7 +65,7 @@ from_json(RD, #ctx{user_id = undefined, user = User} = Ctx) ->
{struct, Json} = mochijson2:decode(RawJson),
Password = proplists:get_value(<<"password">>, Json),
ok = snowflake_user:assign(User#user.id, Password),
- NewJson = mochijson2:encode({struct, [{<<"user_id">>, User#user.id},
+ NewJson = mochijson2:encode({struct, [{<<"userId">>, User#user.id},
{<<"password">>, Password}]}),
RD2 = wrq:set_resp_body(NewJson, RD),
{true, RD2, Ctx};
@@ -75,7 +75,7 @@ from_json(RD, Ctx) ->
{struct, Json} = mochijson2:decode(RawJson),
Password = proplists:get_value(<<"password">>, Json),
ok = snowflake_user:assign(list_to_binary(Ctx#ctx.user_id), Password),
- NewJson = mochijson2:encode({struct, [{<<"user_id">>, list_to_binary(Ctx#ctx.user_id)},
+ NewJson = mochijson2:encode({struct, [{<<"userId">>, list_to_binary(Ctx#ctx.user_id)},
{<<"password">>, Password}]}),
RD2 = wrq:set_resp_body(NewJson, RD),
RD3 = wrq:set_resp_header("Location", "/users/" ++ Ctx#ctx.user_id, RD2),
アップデート用のパッケージを作成します:
$ ./rebar generate ==> rel (generate) $ ./rebar generate-appups previous_release=snowflake_1 ==> rel (generate-appups) Generated appup for snowflake Appup generation complete $ ./rebar generate -f ==> rel (generate) $ ./rebar generate-upgrade previous_release=snowflake_1 ==> rel (generate-upgrade) snowflake_2 upgrade package created $ cp rel/snowflake_2.tar.gz rel/snowflake_1/releases
ポイントは rel/snowflake_1 の releases の下に作成したアップデートパッケージを置くことです。
起動しているサーバで以下のコマンドを実行します:
Eshell V5.9.3 (abort with ^G) ([email protected])1> release_handler:which_releases(). [{"snowflake","1", ["kernel-2.15.3","stdlib-1.18.3","sasl-2.2.1","crypto-2.2", "inets-5.9.2","mochiweb-1.5.1p3","webmachine-1.9.3", "snowflake-1","asn1-1.8","compiler-4.8.2","mnesia-4.7.1", "public_key-0.17","runtime_tools-1.8.9","ssl-5.1.1", "syntax_tools-1.6.9","tools-2.6.8","xmerl-1.3.2"], permanent}] ([email protected])2> release_handler:unpack_release("snowflake_2"). {ok,"2"} ([email protected])3> release_handler:install_release("2"). {ok,"1",[]} ([email protected])4> release_handler:which_releases(). [{"snowflake","2", ["kernel-2.15.3","stdlib-1.18.3","sasl-2.2.1","crypto-2.2", "inets-5.9.2","mochiweb-1.5.1p3","webmachine-1.9.3", "snowflake-2","asn1-1.8","compiler-4.8.2","mnesia-4.7.1", "public_key-0.17","runtime_tools-1.8.9","ssl-5.1.1", "syntax_tools-1.6.9","tools-2.6.8","xmerl-1.3.2"], current}, {"snowflake","1", ["kernel-2.15.3","stdlib-1.18.3","sasl-2.2.1","crypto-2.2", "inets-5.9.2","mochiweb-1.5.1p3","webmachine-1.9.3", "snowflake-1","asn1-1.8","compiler-4.8.2","mnesia-4.7.1", "public_key-0.17","runtime_tools-1.8.9","ssl-5.1.1", "syntax_tools-1.6.9","tools-2.6.8","xmerl-1.3.2"], permanent}] ([email protected])5>
release_handler:unpack_relase/1 で解凍して release_handler:install_release/1 でバージョン番号を指定してインストールします。
user_id が userId になっていることを確認します
userId になってる:
$ http GET localhost:8080/users/1234 HTTP/1.1 200 OK Content-Length: 35 Content-Type: application/json Date: Thu, 21 Feb 2013 06:13:51 GMT Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue) { "password": "pass", "userId": "1234" }