使用erlang开发服务端の代码热升级
来源:互联网 发布:linux find 文件 编辑:程序博客网 时间:2024/06/03 19:29
之前写过一个简单的使用ranch tcp开发服务端,http://blog.csdn.net/huang1196/article/details/38401197
运行代码后发现如果对源文件修改并make之后,代码不会自动热升级。实际上当然不会这样,一直这么认为的原因在于用mochiweb开发时每次在eclipse下保存,console都会马上提示reloading XXX,对代码进行热升级;或者直接make,也能进行代码热升级。实际上mochiweb用了个简单的reloader实现了此功能,我们只需要把其源码copy到自己的项目中并在启动服务端时将reloader一同启动即可。
start.sh
erl -pa ebin deps/*/ebin +K true +P 199999 \ -sname game_server \ -s game -s reloader
其实现很好理解,通过code:all_loaded()得到所有Module对应的文件名,通过其修改时间判断该文件是否被更改,若更改则通过code:purge/1移除旧code,通过code:load_file/1加载新code。
reloader.erl
%% @copyright 2007 Mochi Media, Inc.%% @author Matthew Dempsky <matthew@mochimedia.com>%%%% @doc Erlang module for automatically reloading modified modules%% during development.-module(reloader).-author("Matthew Dempsky <matthew@mochimedia.com>").-include_lib("kernel/include/file.hrl").-behaviour(gen_server).-export([start/0, start_link/0]).-export([stop/0]).-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).-export([all_changed/0]).-export([is_changed/1]).-export([reload_modules/1]).-record(state, {last, tref}).%% External API%% @spec start() -> ServerRet%% @doc Start the reloader.start() -> gen_server:start({local, ?MODULE}, ?MODULE, [], []).%% @spec start_link() -> ServerRet%% @doc Start the reloader.start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).%% @spec stop() -> ok%% @doc Stop the reloader.stop() -> gen_server:call(?MODULE, stop).%% gen_server callbacks%% @spec init([]) -> {ok, State}%% @doc gen_server init, opens the server in an initial state.init([]) -> {ok, TRef} = timer:send_interval(timer:seconds(1), doit), {ok, #state{last = stamp(), tref = TRef}}.%% @spec handle_call(Args, From, State) -> tuple()%% @doc gen_server callback.handle_call(stop, _From, State) -> {stop, shutdown, stopped, State};handle_call(_Req, _From, State) -> {reply, {error, badrequest}, State}.%% @spec handle_cast(Cast, State) -> tuple()%% @doc gen_server callback.handle_cast(_Req, State) -> {noreply, State}.%% @spec handle_info(Info, State) -> tuple()%% @doc gen_server callback.handle_info(doit, State) -> Now = stamp(), _ = doit(State#state.last, Now), {noreply, State#state{last = Now}};handle_info(_Info, State) -> {noreply, State}.%% @spec terminate(Reason, State) -> ok%% @doc gen_server termination callback.terminate(_Reason, State) -> {ok, cancel} = timer:cancel(State#state.tref), ok.%% @spec code_change(_OldVsn, State, _Extra) -> State%% @doc gen_server code_change callback (trivial).code_change(_Vsn, State, _Extra) -> {ok, State}.%% @spec reload_modules([atom()]) -> [{module, atom()} | {error, term()}]%% @doc code:purge/1 and code:load_file/1 the given list of modules in order,%% return the results of code:load_file/1.reload_modules(Modules) -> [begin code:purge(M), code:load_file(M) end || M <- Modules].%% @spec all_changed() -> [atom()]%% @doc Return a list of beam modules that have changed.all_changed() -> [M || {M, Fn} <- code:all_loaded(), is_list(Fn), is_changed(M)].%% @spec is_changed(atom()) -> boolean()%% @doc true if the loaded module is a beam with a vsn attribute%% and does not match the on-disk beam file, returns false otherwise.is_changed(M) -> try module_vsn(M:module_info()) =/= module_vsn(code:get_object_code(M)) catch _:_ -> false end.%% Internal APImodule_vsn({M, Beam, _Fn}) -> {ok, {M, Vsn}} = beam_lib:version(Beam), Vsn;module_vsn(L) when is_list(L) -> {_, Attrs} = lists:keyfind(attributes, 1, L), {_, Vsn} = lists:keyfind(vsn, 1, Attrs), Vsn.doit(From, To) -> [case file:read_file_info(Filename) of {ok, #file_info{mtime = Mtime}} when Mtime >= From, Mtime < To -> reload(Module); {ok, _} -> unmodified; {error, enoent} -> %% The Erlang compiler deletes existing .beam files if %% recompiling fails. Maybe it's worth spitting out a %% warning here, but I'd want to limit it to just once. gone; {error, Reason} -> io:format("Error reading ~s's file info: ~p~n", [Filename, Reason]), error end || {Module, Filename} <- code:all_loaded(), is_list(Filename)].reload(Module) -> io:format("Reloading ~p ...", [Module]), code:purge(Module), case code:load_file(Module) of {module, Module} -> io:format(" ok.~n"), case erlang:function_exported(Module, test, 0) of true -> io:format(" - Calling ~p:test() ...", [Module]), case catch Module:test() of ok -> io:format(" ok.~n"), reload; Reason -> io:format(" fail: ~p.~n", [Reason]), reload_but_test_failed end; false -> reload end; {error, Reason} -> io:format(" fail: ~p.~n", [Reason]), error end.stamp() -> erlang:localtime().%%%% Tests%%-ifdef(TEST).-include_lib("eunit/include/eunit.hrl").-endif.
0 0
- 使用erlang开发服务端の代码热升级
- 使用erlang开发服务端の使用rebar生成release
- 使用erlang ranch tcp开发服务端
- 使用erlang ranch tcp开发服务端
- 再谈Erlang代码热替换
- Erlang 热补丁原理及升级方案.
- erlang中的代码热替换实践——动态升级尾递归中的用来记录状态的Record
- Erlang学习:游戏服务端学习代码
- Erlang服务端开发(无需Erlang基础)笔试题
- 手游服务端代码热部署
- [Erlang 0010] Erlang 热更新
- Learn You Some Erlang for Great Good-笔记1-Erlang热代码加载
- 热升级
- Erlang 热更新
- Erlang OTP 热更新
- Erlang 热更新
- Erlang 热更新
- erlang热更新
- MVC设计模式
- 字符串处理
- C_C语言宏的定义与使用范例
- 百度分享相关1
- 树状数组
- 使用erlang开发服务端の代码热升级
- SDK详解
- html-form-radio,checkbox,hidden,submit,抓包---ShinePans
- [深入浅出Cocoa]iOS网络编程之CFNetwork
- 聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore
- Ssh 常用用法小结
- oracle利用行号创建id根据id分页
- 百度分享相关2
- cpu使用率与cpu Load Average区别