Skip to content
Browse files

elib 1.7.0 with round robin server

  • Loading branch information...
1 parent 997e156 commit 48b0260f3e3babd36cc131d57827cfb633348b11 @japerk committed
Showing with 98 additions and 14 deletions.
  1. +5 −5 ebin/elib.app
  2. +9 −1 ebin/elib.appup
  3. +16 −8 src/erlport_server.erl
  4. +68 −0 src/round_robin_server.erl
View
10 ebin/elib.app
@@ -1,14 +1,14 @@
{application, elib, [
{description, "Extended Erlang library modules"},
- {vsn, "1.6.4"},
+ {vsn, "1.7.0"},
{mod, {elib, []}},
{registered, [elib_sup, timeout_server]},
{applications, [kernel, stdlib]},
{modules, [
- datetime, edict, efile, elib, elib_sup, elists, emath, emod, emp2,
- erlport_server, estring, esys, etable, etest, gen_cache, geohash, ots,
- plists, ptable, uri_server, reltools, timeout_server,
- delegation_server, baktools, rrule
+ baktools, datetime, delegation_server, edict, efile, elib,
+ elib_sup, elists, emath, emod, emp2, erlport_server, estring, esys,
+ etable, etest, gen_cache, geohash, ots, plists, ptable, uri_server,
+ reltools, round_robin_server, rrule, timeout_server
]},
{env, []}
]}.
View
10 ebin/elib.appup
@@ -1,5 +1,9 @@
-{"1.6.4", [
+{"1.7.0", [
% upgrade instructions
+ {"1.6.4", [
+ {load_module, erlport_server},
+ {add_module, round_robin_server}
+ ]},
{"1.6.3", [
{add_module, geohash},
{load_module, estring}
@@ -42,6 +46,10 @@
{"1.5.10", [{load_module, etable}]}
], [
% downgrade instructions
+ {"1.6.4", [
+ {load_module, erlport_server},
+ {delete_module, round_robin_server}
+ ]},
{"1.6.3", [
{delete_module, geohash},
{load_module, estring}
View
24 src/erlport_server.erl
@@ -2,23 +2,31 @@
-behaviour(gen_server).
--export([start_link/3, start_link_opts/3, request/2, request/3]).
+-export([start_link/2, start_link/3, start_link_port_opts/2, start_link_port_opts/3]).
+-export([request/2, request/3]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+-define(PORT_OPTS(PyPath), [{packet, 4}, binary, {env, [{"PYTHONPATH", PyPath}]}]).
+
%%%%%%%%%%%%%%%%
%% public api %%
%%%%%%%%%%%%%%%%
-start_link(ServerName, PySpawn, PyPath) ->
- PortOpts = [{packet, 4}, binary, {env, [{"PYTHONPATH", PyPath}]}],
- start_link_opts(ServerName, PySpawn, PortOpts).
+start_link(PySpawn, PyPath) ->
+ start_link_port_opts(PySpawn, ?PORT_OPTS(PyPath)).
+
+start_link(Name, PySpawn, PyPath) ->
+ start_link_port_opts(Name, PySpawn, ?PORT_OPTS(PyPath)).
+
+start_link_port_opts(PySpawn, PortOpts) ->
+ gen_server:start_link(?MODULE, {PySpawn, PortOpts}, []).
-start_link_opts(ServerName, PySpawn, PortOpts) ->
- gen_server:start_link({local, ServerName}, ?MODULE, {PySpawn, PortOpts}, []).
+start_link_port_opts(Name, PySpawn, PortOpts) ->
+ gen_server:start_link(Name, ?MODULE, {PySpawn, PortOpts}, []).
-request(ServerRef, Request) -> gen_server:call(ServerRef, Request, infinity).
+request(Ref, Request) -> gen_server:call(Ref, Request, infinity).
-request(ServerRef, Request, Timeout) -> gen_server:call(ServerRef, Request, Timeout).
+request(Ref, Request, Timeout) -> gen_server:call(Ref, Request, Timeout).
%%%%%%%%%%%%%%%%
%% gen_server %%
View
68 src/round_robin_server.erl
@@ -0,0 +1,68 @@
+%% @doc Round robin server starts child processes and creates a queue of Pids.
+%% On each call to next(), the Pid at the front of the queue is returned and
+%% moved to the back of the queue. If a child process exits, it is removed from
+%% the queue and a new child process is started.
+-module(round_robin_server).
+
+-behaviour(gen_server).
+
+-export([start_link/2, start_link/3]).
+-export([next/0, next/1, next/2]).
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+
+%%%%%%%%%%%%%%%%
+%% public api %%
+%%%%%%%%%%%%%%%%
+
+start_link(MFA, N) -> gen_server:start_link(?MODULE, {MFA, N}, []).
+
+%% @doc Start round robin server named Name with N children.
+%% MFA must return {ok, Pid}.
+start_link(Name, MFA, N) -> gen_server:start_link(Name, ?MODULE, {MFA, N}, []).
+
+next() -> next(?MODULE).
+
+next(Ref) -> next(Ref, infinity).
+
+%% @doc Get the next Pid from the server
+next(Ref, Timeout) -> gen_server:call(Ref, next, Timeout).
+
+%%%%%%%%%%%%%%%%
+%% gen_server %%
+%%%%%%%%%%%%%%%%
+
+init({{Mod, Fun, Args}=MFA, N}) ->
+ F = fun(_) ->
+ {ok, Pid} = apply(Mod, Fun, Args),
+ link(Pid),
+ Pid
+ end,
+
+ process_flag(trap_exit, true),
+ Pids = lists:map(F, lists:seq(1, N)),
+ {ok, {MFA, queue:from_list(Pids)}}.
+
+handle_call(next, _From, {MFA, Queue}=State) ->
+ case queue:out(Queue) of
+ {empty, Queue} -> {reply, empty, State};
+ % empty at front of queue is returned and put at the end of queue
+ {{value, Pid}, Q2} -> {reply, Pid, {MFA, queue:in(Pid, Q2)}}
+ end;
+handle_call(_, _, State) ->
+ {reply, undefined, State}.
+
+handle_cast(_, State) -> {noreply, State}.
+
+handle_info({'EXIT', Pid, Reason}, {{Mod, Fun, Args}=MFA, Queue}) ->
+ error_logger:warning_report([?MODULE, {child_exit, Pid}, {reason, Reason}]),
+ F = fun(P) -> P == Pid end,
+ Q2 = queue:filter(F, Queue),
+ {ok, Pid2} = apply(Mod, Fun, Args),
+ link(Pid2),
+ {noreply, {MFA, queue:in(Pid2, Q2)}};
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_, _) -> ok.
+
+code_change(_, State, _) -> {ok, State}.

0 comments on commit 48b0260

Please sign in to comment.
Something went wrong with that request. Please try again.