Created
March 30, 2009 14:11
-
-
Save jasonroelofs/87804 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% | |
%% Ad-hoc hot-code swap upgrade definitions file. Unlike .appup and .relup, | |
%% this is a pure Erlang file. Use this module to define how an upgrade is supposed | |
%% to take place for this system. | |
%% | |
%% Usage of this module is simple. You need to define up() and down() methods for | |
%% each version of the application. On an upgrade, the upgrade_manager will call | |
%% up(NewVsn) for upgrades. If you need to roll back, it will call down(NewVsn) | |
%% (with NewVsn being the version defined in your .app file). | |
%% | |
%% For example, to upgrade from version "0.1" to "0.2", you need to define: | |
%% | |
%% up("0.2") -> | |
%% [update_manager commands]. | |
%% down("0.2") -> | |
%% [update_manager commands for downgrading to 0.1]. | |
%% | |
%% See upgrade_manager for the avilable commands | |
-module(migrations). | |
-export([up/1, down/1]). | |
%% | |
%% Define how an application upgrades to a given version from the previous | |
%% version. It's expected that the application is currently at the version | |
%% previous (if versions are 0.1, 0.2, 0.3 and you're deploying 0.4, it's assumed | |
%% that the app is at 0.3). | |
%% | |
up("0.2") -> | |
upgrade_manager:upgrade([{reload_process, video_dispatcher}]); | |
up(Vsn) -> | |
io:format("Don't know how to upgrade to version ~p~n", [Vsn]). | |
%% | |
%% Downgrade the application from the passed in version | |
%% | |
down("0.2") -> | |
upgrade_manager:upgrade([{reload_process, video_dispatcher}]); | |
down(Vsn) -> | |
io:format("Don't know how to downgrade from version ~p~n", [Vsn]). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% | |
%% This module is for running real-time code upgrades on the system. | |
%% Actual upgrade code paths are defined in the migrations module. | |
%% | |
%% Upgrade your system by calling: | |
%% | |
%% upgrade_manager:migrate(up / down, Version). | |
%% | |
-module(upgrade_manager). | |
-export([migrate/2, upgrade/1,print_message/1]). | |
%% | |
%% Top-level migration management function. This takes care of replacing code paths, | |
%% reloading this module, and then running the appropriate migration version as defined | |
%% below in up() and down(). | |
%% | |
%% Calling this is simple: | |
%% | |
%% migrations:migrate(up / down, Vsn) | |
%% | |
migrate(Path, Version) -> | |
% Replace code dir to new version | |
CurrentPath = code:lib_dir(video_dispatcher), | |
Tokens = string:tokens(CurrentPath, "-"), | |
BasePath = string:join(lists:delete(lists:last(Tokens), Tokens), "-"), | |
NewPath = string:join([BasePath, Version], "-"), | |
% Sanity check - ensure the new version directory actually exists | |
case file:read_file_info(NewPath) of | |
{error, Error} -> | |
io:format("Was unable to open the directory ~p, given the error ~p~n", [NewPath, Error]); | |
{ok, _} -> | |
io:format("Now migrating to version ~p~n", [Version]), | |
code:replace_path(video_dispatcher, NewPath), | |
% Reload this class | |
c:l(migrations), | |
% Call the migration | |
apply(migrations, Path, [Version]) | |
end. | |
%% | |
%% Upgrade the system, following the rules passed into this method. | |
%% Arguments should be formatted much in the same way an .appup file | |
%% is formatted. This module supports the following commands: | |
%% | |
%% {reload_process, ProcName} - Reload a module that's also a process | |
%% {reload_module, Module} - Reload a module | |
%% | |
%% Args = [Arg] | |
%% Arg = term() | |
%% | |
upgrade(Args) -> | |
process_args(Args). | |
print_message(Message) -> | |
io:format("Message: ~p~n", [Message]). | |
%% | |
%% Private methods | |
%% | |
%% | |
%% Process each argument | |
%% | |
process_args([]) -> | |
ok; | |
process_args([Arg | Rest]) -> | |
case Arg of | |
{reload_process, ProcName} -> | |
reload_process(ProcName); | |
{reload_module, Module} -> | |
reload_module(Module); | |
Any -> | |
% Eh, ignore commands we don't expect | |
io:format("Unknown command ~p, ignored~n", [Any]) | |
end, | |
process_args(Rest). | |
% Reload a given module | |
% This simply suspends the module's process, loads the code, | |
% and resumes the process | |
reload_process(Name) -> | |
% Get rid of any stale code from last update | |
code:purge(Name), | |
% Suspend processes | |
sys:suspend(whereis(Name)), | |
% Load new code into the VM | |
reload_module(Name), | |
% Fire off code change message | |
sys:change_code(Name, Name, vsn, vsn), | |
% Start our process back up | |
sys:resume(whereis(Name)), | |
% Clean up all code we can, leaving that which might | |
% be still in use by processes | |
code:soft_purge(Name). | |
% Reload pure module code. To be used when reload a module that | |
% is not a process, such as this one | |
reload_module(Module) -> | |
c:l(Module). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment