Skip to content

Commit b956efa

Browse files
committed
working external handlers from config
1 parent fda943f commit b956efa

File tree

8 files changed

+110
-66
lines changed

8 files changed

+110
-66
lines changed

bin/ernie

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,14 @@ OptionParser.new do |opts|
4242
opts.banner = help
4343
opts.version = version
4444

45-
opts.on("-h HANDLER", "--handler HANDLER", "Handler ruby file") do |x|
46-
options[:handler] = x
45+
opts.on("-c CONFIG", "--config CONFIG", "Config file") do |x|
46+
options[:config] = x
4747
end
4848

4949
opts.on("-p PORT", "--port PORT", "Port") do |x|
5050
options[:port] = x
5151
end
5252

53-
opts.on("-n NUMBER", "--number NUMBER", "Number of handler instances") do |x|
54-
options[:number] = x
55-
end
56-
5753
opts.on("-l LOGLEVEL", "--log-level LOGLEVEL", "Log level (0-4)") do |x|
5854
options[:log_level] = x
5955
end
@@ -81,14 +77,13 @@ if command = ARGV[0]
8177
svc = BERTRPC::Service.new('localhost', port)
8278
puts svc.call.__admin__.send(command.gsub(/-/, '_'))
8379
else
84-
if !options[:handler]
85-
puts "A handler must be specified: ernie -h /path/to/handler.rb"
80+
if !options[:config]
81+
puts "A config file must be specified: ernie -c /path/to/config.yml"
8682
exit(1)
8783
end
8884

89-
handler = options[:handler]
85+
config = options[:config]
9086
port = options[:port] || DEFAULT_PORT
91-
number = options[:number] || 1
9287
log_level = options[:log_level] || 2
9388
pidfile = options[:pidfile] ? "-ernie_server_app pidfile \"'#{options[:pidfile]}'\"" : ''
9489
detached = options[:detached] ? '-detached' : ''
@@ -101,8 +96,7 @@ else
10196
#{code_paths}
10297
#{pidfile} \
10398
-ernie_server_app port #{port} \
104-
-ernie_server_app handler '"#{handler}"' \
105-
-ernie_server_app number #{number} \
99+
-ernie_server_app config '"#{config}"' \
106100
-ernie_server_app log_level #{log_level} \
107101
-run ernie_server_app boot}.squeeze(' ')
108102
puts cmd

elib/asset_pool.erl

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
-behaviour(gen_server).
33

44
%% api
5-
-export([start_link/1, start/1, lease/0, return/1, reload_assets/0, idle_worker_count/0]).
5+
-export([start_link/2, lease/1, return/2, reload_assets/1, idle_worker_count/1]).
66

77
%% gen_server callbacks
88
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -16,23 +16,20 @@
1616
%% API
1717
%%====================================================================
1818

19-
start_link(Args) ->
20-
gen_server:start_link({global, ?MODULE}, ?MODULE, Args, []).
19+
start_link(Handler, Count) ->
20+
gen_server:start_link(?MODULE, [Handler, Count], []).
2121

22-
start(Args) ->
23-
gen_server:start({global, ?MODULE}, ?MODULE, Args, []).
22+
lease(Pid) ->
23+
gen_server:call(Pid, lease).
2424

25-
lease() ->
26-
gen_server:call({global, ?MODULE}, {lease}).
25+
return(Pid, Asset) ->
26+
gen_server:call(Pid, {return, Asset}).
2727

28-
return(Asset) ->
29-
gen_server:call({global, ?MODULE}, {return, Asset}).
28+
reload_assets(Pid) ->
29+
gen_server:call(Pid, {reload_assets}).
3030

31-
reload_assets() ->
32-
gen_server:call({global, ?MODULE}, {reload_assets}).
33-
34-
idle_worker_count() ->
35-
gen_server:call({global, ?MODULE}, {idle_worker_count}).
31+
idle_worker_count(Pid) ->
32+
gen_server:call(Pid, {idle_worker_count}).
3633

3734
%%====================================================================
3835
%% gen_server callbacks
@@ -45,11 +42,12 @@ idle_worker_count() ->
4542
%% {stop, Reason}
4643
%% Description: Initiates the server
4744
%%--------------------------------------------------------------------
48-
init([Count, Handler]) ->
45+
init([Handler, Count]) ->
4946
process_flag(trap_exit, true),
5047
error_logger:info_msg("~p starting~n", [?MODULE]),
5148
Token = make_ref(),
5249
Assets = start_handlers(Count, Handler, Token),
50+
logger:debug("Assets = ~p~n", [Assets]),
5351
{ok, #state{assets = Assets, handler = Handler, token = Token}}.
5452

5553
%%--------------------------------------------------------------------
@@ -61,7 +59,8 @@ init([Count, Handler]) ->
6159
%% {stop, Reason, State}
6260
%% Description: Handling call messages
6361
%%--------------------------------------------------------------------
64-
handle_call({lease}, _From, State) ->
62+
handle_call(lease, _From, State) ->
63+
logger:debug("Leasing...~n", []),
6564
Token = State#state.token,
6665
case queue:out(State#state.assets) of
6766
{{value, Asset}, Assets2} ->
@@ -140,4 +139,4 @@ start_handlers(Assets, Count, Handler, Token) ->
140139
start_handlers(Assets2, Count - 1, Handler, Token).
141140

142141
create_asset(Handler, Token) ->
143-
{asset, port_wrapper:wrap_link("ruby " ++ Handler), Token}.
142+
{asset, port_wrapper:wrap_link(Handler), Token}.

elib/asset_pool_sup.erl

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
-module(asset_pool_sup).
22
-behaviour(supervisor).
3-
-export([start_link/0, init/1]).
3+
-export([start_link/2, init/1]).
44

5-
start_link() ->
6-
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
5+
start_link(Handler, Number) ->
6+
supervisor:start_link(?MODULE, [Handler, Number]).
77

8-
init([]) ->
9-
{ok, Handler} = application:get_env(ernie_server_app, handler),
8+
init([Handler, Number]) ->
109
io:format("Using handler ~p~n", [Handler]),
11-
{ok, Number} = application:get_env(ernie_server_app, number),
1210
io:format("Using ~p handler instances~n", [Number]),
1311
{ok, {{one_for_one, 1, 60},
14-
[{asset_pool, {asset_pool, start_link, [[Number, Handler]]},
12+
[{asset_pool, {asset_pool, start_link, [Handler, Number]},
1513
permanent, brutal_kill, worker, [asset_pool]}]}}.

elib/config.erl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-module(config).
2+
-export([load/1]).
3+
4+
load(ConfigFile) ->
5+
{ok, Configs} = file:consult(ConfigFile),
6+
Configs2 = lists:map((fun load_single/1), Configs),
7+
{ok, Configs2}.
8+
9+
load_single(Config) ->
10+
case proplists:get_value(type, Config) of
11+
native ->
12+
verify(native, Config),
13+
CodePaths = proplists:get_value(codepaths, Config),
14+
lists:each(fun(X) -> code:add_patha(X) end, CodePaths),
15+
Config;
16+
extern ->
17+
verify(extern, Config),
18+
Handler = proplists:get_value(command, Config),
19+
Number = proplists:get_value(count, Config),
20+
{ok, SupPid} = asset_pool_sup:start_link(Handler, Number),
21+
[{_Id, ChildPid, _Type, _Modules}] = supervisor:which_children(SupPid),
22+
[{pid, ChildPid} | Config]
23+
end.
24+
25+
verify(native, _Config) ->
26+
ok;
27+
verify(extern, _Config) ->
28+
ok.

elib/ernie_server.erl

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010

1111
-record(state, {lsock = undefined,
1212
pending = queue:new(),
13-
count = 0}).
13+
count = 0,
14+
map = undefined}).
1415

1516
-record(request, {sock = undefined,
1617
info = undefined,
@@ -43,12 +44,14 @@ asset_freed() ->
4344
%% {stop, Reason}
4445
%% Description: Initiates the server
4546
%%--------------------------------------------------------------------
46-
init([Port]) ->
47+
init([Port, Configs]) ->
4748
process_flag(trap_exit, true),
4849
error_logger:info_msg("~p starting~n", [?MODULE]),
4950
{ok, LSock} = try_listen(Port, 500),
5051
spawn(fun() -> loop(LSock) end),
51-
{ok, #state{lsock = LSock}}.
52+
Map = init_map(Configs),
53+
io:format("pidmap = ~p~n", [Map]),
54+
{ok, #state{lsock = LSock, map = Map}}.
5255

5356
%%--------------------------------------------------------------------
5457
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
@@ -73,19 +76,11 @@ handle_cast({process, Sock}, State) ->
7376
State2 = receive_term(Request, State),
7477
{noreply, State2};
7578
handle_cast({asset_freed}, State) ->
76-
case queue:is_empty(State#state.pending) of
77-
false ->
78-
case asset_pool:lease() of
79-
{ok, Asset} ->
80-
{{value, Request}, Pending2} = queue:out(State#state.pending),
81-
% io:format("d", []),
82-
spawn(fun() -> process_now(Request, Asset) end),
83-
{noreply, State#state{pending = Pending2}};
84-
empty ->
85-
% io:format(".", []),
86-
{noreply, State}
87-
end;
88-
true ->
79+
case queue:out(State#state.pending) of
80+
{{value, Request}, Pending2} ->
81+
State2 = process_request(Request, State#state{pending = Pending2}),
82+
{noreply, State2};
83+
{empty, _Pending} ->
8984
{noreply, State}
9085
end;
9186
handle_cast(_Msg, State) -> {noreply, State}.
@@ -101,6 +96,14 @@ code_change(_OldVersion, State, _Extra) -> {ok, State}.
10196
%% Internal
10297
%%====================================================================
10398

99+
extract_mapping(Config) ->
100+
Pid = proplists:get_value(pid, Config),
101+
Mods = proplists:get_value(modules, Config),
102+
lists:map(fun(X) -> {X, Pid} end, Mods).
103+
104+
init_map(Configs) ->
105+
lists:foldl(fun(X, Acc) -> Acc ++ extract_mapping(X) end, [], Configs).
106+
104107
try_listen(Port, 0) ->
105108
error_logger:error_msg("Could not listen on port ~p~n", [Port]),
106109
{error, "Could not listen on port"};
@@ -166,45 +169,64 @@ receive_term(Request, State) ->
166169

167170
process_request(Request, State) ->
168171
ActionTerm = binary_to_term(Request#request.action),
172+
close_if_cast(ActionTerm, Request),
173+
{_Type, Mod, _Fun, _Args} = ActionTerm,
174+
Pid = proplists:get_value(Mod, State#state.map),
175+
case Pid of
176+
undefined ->
177+
logger:debug("Dispatching to native module~n", []),
178+
process_native_request(Request, State);
179+
ValidPid ->
180+
logger:debug("Found extern pid ~p~n", [ValidPid]),
181+
process_extern_request(ValidPid, Request, State)
182+
end.
183+
184+
close_if_cast(ActionTerm, Request) ->
169185
case ActionTerm of
170186
{cast, _Mod, _Fun, _Args} ->
171187
Sock = Request#request.sock,
172188
gen_tcp:send(Sock, term_to_binary({noreply})),
173189
ok = gen_tcp:close(Sock),
174-
logger:debug("Closing cast.~n", []);
190+
logger:debug("Closed cast.~n", []);
175191
_Any ->
176192
ok
177-
end,
193+
end.
194+
195+
process_native_request(_Request, State) ->
196+
State.
197+
198+
process_extern_request(Pid, Request, State) ->
178199
case queue:is_empty(State#state.pending) of
179200
false ->
201+
logger:debug("Pre queueing request for pool ~p~n", [Pid]),
180202
Pending2 = queue:in(Request, State#state.pending),
181-
% io:format("Q", []),
182203
State#state{pending = Pending2};
183204
true ->
184-
try_process_now(Request, State)
205+
try_process_now(Pid, Request, State)
185206
end.
186207

187-
try_process_now(Request, State) ->
208+
try_process_now(Pid, Request, State) ->
188209
Count = State#state.count,
189210
State2 = State#state{count = Count + 1},
190-
case asset_pool:lease() of
211+
logger:debug("Count = ~p~n", [Count + 1]),
212+
case asset_pool:lease(Pid) of
191213
{ok, Asset} ->
192-
% io:format("i", []),
193-
spawn(fun() -> process_now(Request, Asset) end),
214+
logger:debug("Leased asset for pool ~p~n", [Pid]),
215+
spawn(fun() -> process_now(Pid, Request, Asset) end),
194216
State2;
195217
empty ->
196-
% io:format("q", []),
218+
logger:debug("Post queueing request for pool ~p~n", [Pid]),
197219
Pending2 = queue:in(Request, State#state.pending),
198220
State2#state{pending = Pending2}
199221
end.
200222

201-
process_now(Request, Asset) ->
223+
process_now(Pid, Request, Asset) ->
202224
try unsafe_process_now(Request, Asset) of
203225
_AnyResponse -> ok
204226
catch
205227
_AnyError -> ok
206228
after
207-
asset_pool:return(Asset),
229+
asset_pool:return(Pid, Asset),
208230
ernie_server:asset_freed(),
209231
gen_tcp:close(Request#request.sock)
210232
end.

elib/ernie_server_app.erl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ boot() ->
88

99
start(_Type, _Args) ->
1010
logger_sup:start_link(),
11-
ernie_server_sup:start_link(),
12-
asset_pool_sup:start_link().
11+
ernie_server_sup:start_link().
1312

1413
stop(_State) ->
1514
ok.

elib/ernie_server_sup.erl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ init([]) ->
1414
ok = file:write_file(Location, list_to_binary(Pid));
1515
undefined -> ok
1616
end,
17+
{ok, Config} = application:get_env(ernie_server_app, config),
18+
{ok, Configs} = config:load(Config),
19+
io:format("~p~n", [Configs]),
1720
{ok, {{one_for_one, 1, 60},
18-
[{ernie_server, {ernie_server, start_link, [[Port]]},
21+
[{ernie_server, {ernie_server, start_link, [[Port, Configs]]},
1922
permanent, brutal_kill, worker, [ernie_server]}]}}.

examples/dsl.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[{modules, [test]}, {type, extern}, {command, "ruby examples/dsl.rb"}, {count, 2}].

0 commit comments

Comments
 (0)