Permalink
Browse files

Add 'deps/esupervisor/' from commit '070a019638154f021c2a6816314a266b…

…a7897611'

git-subtree-dir: deps/esupervisor
git-subtree-mainline: 7d74b00
git-subtree-split: 070a019
  • Loading branch information...
2 parents 7d74b00 + 070a019 commit 2c03aa26f6244a34481d701699186f71daf0095f Yurii Rashkovskii committed Apr 24, 2012
View
2 deps/esupervisor/.gitignore
@@ -0,0 +1,2 @@
+.eunit
+ebin
View
71 deps/esupervisor/README.md
@@ -0,0 +1,71 @@
+esupervisor
+===========
+
+`esupervisor` is an extension of Erlang's `supervisor` API that makes it more convenient.
+
+Features
+--------
+
+* record-based syntax
+
+It allows you to avoid problems with the need to follow the exact order of elements in
+`supervisor` tuples so that you don't have to use (often) inconsistent `CHILD` macros and yet
+describe your supervision items at any level of detail you want
+
+* single callback to describe the entire supervision tree
+
+Instead of scattering your supervision tree across multiple `sup` modules you can have a clear
+view of your entire supervision tree in a single module because `esupervisor` allows you to
+specify supervisors as children.
+
+
+Example
+-------
+
+Define your supervisor:
+
+``` erlang
+-module(my_sup).
+-behaviour(esupervisor).
+-include_lib("esupervisor/include/esupervisor.hrl").
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+start_link() ->
+ esupervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+```
+
+Define your supervision tree:
+
+``` erlang
+init([]) ->
+ #one_for_one{
+ children = [
+ #one_for_one{
+ id = first
+ },
+ #simple_one_for_one{
+ id = some_sup,
+ registered = some_sup,
+ children = [
+ #worker{
+ id = some,
+ restart = permanent,
+ start_func = {some_worker, start_link, []}
+ }
+ ]
+ }
+ ]
+
+ }.
+
+```
+
+The above example will define a `one_for_one` supervisor supervising two other supervisors, `first`
+and `some_sup` (registered as `some_sup`), and `some_sup` sofo supervisor supervises worker processes
+that are started with `some_worker:start_link`.
View
69 deps/esupervisor/include/esupervisor.hrl
@@ -0,0 +1,69 @@
+-record(child, {
+ id :: term(),
+ start_func :: {module(), atom(), [term()] | undefined } | undefined,
+ restart = permanent :: permanent | transient | temporary,
+ shutdown = 5000 :: brutal_kill | timeout() | infinity,
+ type :: worker | supervisor,
+ modules :: [module()] | dynamic | undefined
+ }).
+
+-record(worker, {
+ id :: term(),
+ start_func :: {module(), atom(), [term()] | undefined } | undefined,
+ restart = permanent:: permanent | transient | temporary,
+ shutdown = 5000 :: brutal_kill | timeout() | infinity,
+ modules :: [module()] | dynamic | undefined
+ }).
+
+-record(supervisor, {
+ id :: term(),
+ registered = false :: term(),
+ restart_strategy = one_for_one :: one_for_one | one_for_all | rest_for_one |
+ simple_one_for_one,
+ max_restarts = {1, 60} :: {pos_integer(), pos_integer()},
+ children = [] :: [esupervisor:supervisable()],
+ %%
+ restart = permanent :: permanent | transient | temporary,
+ shutdown = infinity :: brutal_kill | timeout() | infinity
+ }).
+
+-record(one_for_one, {
+ id :: term(),
+ registered = false :: term(),
+ max_restarts = {1,60} :: {pos_integer(), pos_integer()},
+ children = [] :: [esupervisor:supervisable()],
+ %%
+ restart = permanent :: permanent | transient | temporary,
+ shutdown = infinity :: brutal_kill | timeout() | infinity
+ }).
+
+-record(one_for_all, {
+ id :: term(),
+ registered = false :: term(),
+ max_restarts = {1,60} :: {pos_integer(), pos_integer()},
+ children = [] :: [esupervisor:supervisable()],
+ %%
+ restart = permanent :: permanent | transient | temporary,
+ shutdown = infinity :: brutal_kill | timeout() | infinity
+ }).
+
+-record(rest_for_one, {
+ id :: term(),
+ registered = false :: term(),
+ max_restarts = {1,60} :: {pos_integer(), pos_integer()},
+ children = [] :: [esupervisor:supervisable()],
+ %%
+ restart = permanent :: permanent | transient | temporary,
+ shutdown = infinity :: brutal_kill | timeout() | infinity
+ }).
+
+-record(simple_one_for_one, {
+ id :: term(),
+ registered = false :: term(),
+ max_restarts = {1,60} :: {pos_integer(), pos_integer()},
+ children = [] :: [esupervisor:supervisable()],
+ %%
+ restart = permanent :: permanent | transient | temporary,
+ shutdown = infinity :: brutal_kill | timeout() | infinity
+ }).
+
View
11 deps/esupervisor/src/esupervisor.app.src
@@ -0,0 +1,11 @@
+{application, esupervisor,
+ [
+ {description, "'Least surprise' supervisor API"},
+ {vsn, git},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib
+ ]},
+ {env, []}
+ ]}.
View
224 deps/esupervisor/src/esupervisor.erl
@@ -0,0 +1,224 @@
+-module(esupervisor).
+-behaviour(supervisor).
+-include_lib("esupervisor/include/esupervisor.hrl").
+
+-export([start_link/2, start_link/3]).
+-export([behaviour_info/1]).
+-export([start_sup/2]).
+-export([spec/1]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-export_type([supervisable/0]).
+
+-type supervisor() :: #supervisor{} | #one_for_one{} |
+ #one_for_all{} | #rest_for_one{} |
+ #simple_one_for_one{}.
+
+-type child() :: #child{} | #worker{}.
+
+-type supervisable() :: child() | supervisor().
+
+behaviour_info(callbacks) ->
+ [{init,1}];
+behaviour_info(_) ->
+ undefined.
+
+-include_lib("eunit/include/eunit.hrl").
+
+init({spec, Spec}) ->
+ init_result(Spec);
+init({Module, Args}) ->
+ init_result(Module:init(Args)).
+
+-spec start_link(module(), term()) -> supervisor:start_link_ret().
+
+start_link(Module, Args) ->
+ supervisor:start_link(?MODULE, {Module, Args}).
+
+start_link(SupName, Module, Args) ->
+ supervisor:start_link(SupName, ?MODULE, {Module, Args}).
+
+-spec start_sup(atom() | undefined, supervisor()) -> {ok, pid()}.
+
+start_sup(false, SupervisorSpec) ->
+ supervisor:start_link(?MODULE, {spec, SupervisorSpec});
+start_sup(Reg, SupervisorSpec) ->
+ supervisor:start_link({local, Reg}, ?MODULE, {spec, SupervisorSpec}).
+
+%% Internal functions
+init_result(ignore) ->
+ ignore;
+init_result(Result) ->
+ {ok, spec(Result)}.
+
+specs([]) ->
+ [];
+specs([Spec|Rest]) ->
+ [spec(Spec)|specs(Rest)].
+
+spec(#worker{
+ id = Id,
+ start_func = StartFunc,
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = Modules
+ }) ->
+ spec(#child{
+ type = worker,
+ id = Id,
+ start_func = StartFunc,
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = Modules
+ });
+spec(#child{
+ id = Id,
+ start_func = undefined
+ } = Child) ->
+ spec(Child#child{ start_func = {Id, start_link, []}});
+spec(#child{
+ id = Id,
+ modules = undefined
+ } = Child) ->
+ spec(Child#child{ modules = [Id] });
+spec(#child{
+ id = Id,
+ start_func = StartFunc,
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = Modules,
+ type = Type
+ }) ->
+ Child = {Id, StartFunc, Restart, Shutdown, Type, Modules},
+ ok = supervisor:check_childspecs([Child]),
+ Child;
+
+spec(#one_for_one{
+ id = Id,
+ max_restarts = MaxRT,
+ children = Children
+ }) ->
+ spec(#supervisor{ id = Id,
+ restart_strategy = one_for_one,
+ max_restarts = MaxRT,
+ children = Children });
+
+spec(#one_for_all{
+ id = Id,
+ max_restarts = MaxRT,
+ children = Children
+ }) ->
+ spec(#supervisor{ id = Id,
+ restart_strategy = one_for_all,
+ max_restarts = MaxRT,
+ children = Children });
+
+spec(#rest_for_one{
+ id = Id,
+ max_restarts = MaxRT,
+ children = Children
+ }) ->
+ spec(#supervisor{ id = Id,
+ restart_strategy = rest_for_one,
+ max_restarts = MaxRT,
+ children = Children });
+
+spec(#simple_one_for_one{
+ id = Id,
+ max_restarts = MaxRT,
+ children = Children
+ }) ->
+ spec(#supervisor{ id = Id,
+ restart_strategy = simple_one_for_one,
+ max_restarts = MaxRT,
+ children = Children });
+
+spec(#supervisor{
+ id = _Id,
+ restart_strategy = Restart,
+ max_restarts = {MaxR, MaxT},
+ children = Children
+ }) ->
+ {{Restart, MaxR, MaxT}, specs(maybe_convert_supervisors(Children))}.
+
+
+maybe_convert_supervisors([]) ->
+ [];
+maybe_convert_supervisors([Spec|Specs]) ->
+ [maybe_convert_supervisor(Spec)|maybe_convert_supervisors(Specs)].
+
+maybe_convert_supervisor(#one_for_one{
+ id = Id,
+ registered = Reg, restart = Restart,
+ shutdown = Shutdown
+ } = Sup) ->
+ #child{
+ id = Id,
+ type = supervisor,
+ start_func = {?MODULE, start_sup, [Reg, Sup]},
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = [?MODULE]
+ };
+
+maybe_convert_supervisor(#one_for_all{
+ id = Id,
+ registered = Reg, restart = Restart,
+ shutdown = Shutdown
+ } = Sup) ->
+ #child{
+ id = Id,
+ type = supervisor,
+ start_func = {?MODULE, start_sup, [Reg, Sup]},
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = [?MODULE]
+ };
+
+maybe_convert_supervisor(#rest_for_one{
+ id = Id,
+ registered = Reg, restart = Restart,
+ shutdown = Shutdown
+ } = Sup) ->
+ #child{
+ id = Id,
+ type = supervisor,
+ start_func = {?MODULE, start_sup, [Reg, Sup]},
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = [?MODULE]
+ };
+
+maybe_convert_supervisor(#simple_one_for_one{
+ id = Id,
+ registered = Reg, restart = Restart,
+ shutdown = Shutdown
+ } = Sup) ->
+ #child{
+ id = Id,
+ type = supervisor,
+ start_func = {?MODULE, start_sup, [Reg, Sup]},
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = [?MODULE]
+ };
+
+maybe_convert_supervisor(#supervisor{
+ id = Id,
+ registered = Reg, restart = Restart,
+ shutdown = Shutdown
+ } = Sup) ->
+ #child{
+ id = Id,
+ type = supervisor,
+ start_func = {?MODULE, start_sup, [Reg, Sup]},
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = [?MODULE]
+ };
+
+
+maybe_convert_supervisor(Other) ->
+ Other.
View
28 deps/esupervisor/test/gen_supervisor_tests.erl
@@ -0,0 +1,28 @@
+-module(gen_supervisor_tests).
+-include_lib("eunit/include/eunit.hrl").
+
+t_starts_supervisor() ->
+ ?assertMatch([{some_sup, _, _, _},{first, _, _, _}], supervisor:which_children(test_sup)),
+ ?assertMatch(Pid when is_pid(Pid), whereis(some_sup)),
+ ?assertEqual(undefined, whereis(first)).
+
+
+t_nested_supervisor() ->
+ [{some_sup, Pid, _, _},{first, _, _, _}] = supervisor:which_children(test_sup),
+ ?assertMatch([{some, _, _, _}], supervisor:which_children(Pid)).
+
+gen_supervisor_test_() ->
+ {setup,
+ fun () ->
+ application:start(gen_supervisor),
+ {ok, SupPid} = test_sup:start_link(),
+ SupPid
+ end,
+ fun (_SupPid) ->
+ application:stop(gen_supervisor)
+ end,
+ [
+ {"starts supervisor", ?_test(t_starts_supervisor())},
+ {"nested supervisor is handled properly", ?_test(t_nested_supervisor())}
+
+ ]}.
View
39 deps/esupervisor/test/test_sup.erl
@@ -0,0 +1,39 @@
+-module(test_sup).
+-behaviour(esupervisor).
+-include_lib("esupervisor/include/esupervisor.hrl").
+
+%% API
+-export([start_link/0]).
+
+-export([some_start_link/1]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+start_link() ->
+ esupervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+init([]) ->
+ #one_for_one{
+ children = [
+ #one_for_one{
+ id = first
+ },
+ #one_for_one{
+ id = some_sup,
+ registered = some_sup,
+ children = [
+ #worker{
+ id = some,
+ restart = permanent,
+ start_func = {?MODULE, some_start_link, [some]}
+ }
+ ]
+ }
+ ]
+
+ }.
+
+some_start_link(_Name) ->
+ {ok, spawn_link(fun() -> receive nothing -> ok end end)}.
+

0 comments on commit 2c03aa2

Please sign in to comment.