capricorn 0.2.25 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. data/LICENSE +19 -0
  2. data/README.md +1 -0
  3. data/bin/capricorn-app-scaffolder +27 -0
  4. data/bin/capricorn-gem-spec +33 -0
  5. data/bin/capricornctl +12 -0
  6. data/bin/capricornd +31 -0
  7. data/erlang/lib/bert/doc/overview.edoc +4 -0
  8. data/erlang/lib/bert/ebin/bert.app +9 -0
  9. data/erlang/lib/bert/rebar.config +3 -0
  10. data/erlang/lib/bert/src/bert.erl +69 -0
  11. data/erlang/lib/bertio/doc/overview.edoc +4 -0
  12. data/erlang/lib/bertio/ebin/bertio.app +9 -0
  13. data/erlang/lib/bertio/rebar.config +3 -0
  14. data/erlang/lib/bertio/src/bertio.erl +28 -0
  15. data/erlang/lib/bertrpc/doc/overview.edoc +4 -0
  16. data/erlang/lib/bertrpc/ebin/bertrpc.app +12 -0
  17. data/erlang/lib/bertrpc/include/bertrpc.hrl +1 -0
  18. data/erlang/lib/bertrpc/rebar.config +5 -0
  19. data/erlang/lib/bertrpc/src/bertrpc.erl +471 -0
  20. data/erlang/lib/bertrpc/src/bertrpc_hello_world.erl +148 -0
  21. data/erlang/lib/bertrpc/src/fd_tcp.erl +376 -0
  22. data/erlang/lib/capricorn/doc/overview.edoc +4 -0
  23. data/erlang/lib/capricorn/ebin/capricorn.app +56 -0
  24. data/erlang/lib/capricorn/include/capricorn.hrl +76 -0
  25. data/erlang/lib/capricorn/rebar.config +3 -0
  26. data/erlang/lib/capricorn/src/cap_application.erl +170 -0
  27. data/erlang/lib/capricorn/src/cap_cluster.erl +121 -0
  28. data/erlang/lib/capricorn/src/cap_cluster_gems.erl +422 -0
  29. data/erlang/lib/capricorn/src/cap_config.erl +25 -0
  30. data/erlang/lib/capricorn/src/cap_dets_updater.erl +26 -0
  31. data/erlang/lib/capricorn/src/cap_event_sup.erl +35 -0
  32. data/erlang/lib/capricorn/src/cap_events.erl +24 -0
  33. data/erlang/lib/capricorn/src/cap_external_api.erl +87 -0
  34. data/erlang/lib/capricorn/src/cap_external_apps_api.erl +125 -0
  35. data/erlang/lib/capricorn/src/cap_external_gems_api.erl +85 -0
  36. data/erlang/lib/capricorn/src/cap_external_machines_api.erl +18 -0
  37. data/erlang/lib/capricorn/src/cap_gem_utils.erl +111 -0
  38. data/erlang/lib/capricorn/src/cap_internal_api.erl +69 -0
  39. data/erlang/lib/capricorn/src/cap_internal_apps_api.erl +38 -0
  40. data/erlang/lib/capricorn/src/cap_log.erl +113 -0
  41. data/erlang/lib/capricorn/src/cap_machine.erl +338 -0
  42. data/erlang/lib/capricorn/src/cap_machine_apps.erl +410 -0
  43. data/erlang/lib/capricorn/src/cap_machine_apps_sup.erl +57 -0
  44. data/erlang/lib/capricorn/src/cap_sup.erl +200 -0
  45. data/erlang/lib/capricorn/src/cap_util.erl +278 -0
  46. data/erlang/lib/capricorn/src/capricorn.erl +45 -0
  47. data/erlang/lib/capricorn/src/capricorn_app.erl +36 -0
  48. data/erlang/lib/emq/ebin/emq.app +17 -0
  49. data/erlang/lib/emq/src/emq.erl +261 -0
  50. data/erlang/lib/emq/src/emq_app.erl +11 -0
  51. data/erlang/lib/emq/src/emq_pool.erl +178 -0
  52. data/erlang/lib/emq/src/emq_queue.erl +332 -0
  53. data/erlang/lib/emq/src/emq_status.erl +148 -0
  54. data/erlang/lib/emq/src/emq_sup.erl +132 -0
  55. data/erlang/lib/gcd/ebin/gcd.app +18 -0
  56. data/erlang/lib/gcd/include/gcd.hrl +5 -0
  57. data/erlang/lib/gcd/rebar.config +3 -0
  58. data/erlang/lib/gcd/src/gcd.erl +51 -0
  59. data/erlang/lib/gcd/src/gcd_app.erl +13 -0
  60. data/erlang/lib/gcd/src/gcd_event.erl +39 -0
  61. data/erlang/lib/gcd/src/gcd_server.erl +30 -0
  62. data/erlang/lib/gcd/src/gcd_srv.erl +186 -0
  63. data/erlang/lib/gcd/src/gcd_sup.erl +18 -0
  64. data/erlang/rebar +0 -0
  65. data/erlang/rebar.config +9 -0
  66. data/erlang/rel/overlay/bin/capricornd +146 -0
  67. data/erlang/rel/overlay/erts-vsn/bin/erl +34 -0
  68. data/erlang/rel/overlay/erts-vsn/bin/nodetool +80 -0
  69. data/erlang/rel/overlay/etc/capricorn/app.config +59 -0
  70. data/erlang/rel/overlay/etc/capricorn/cluster-vm.args +21 -0
  71. data/erlang/rel/overlay/etc/capricorn/machine-vm.args +21 -0
  72. data/erlang/rel/reltool.config +43 -0
  73. data/ext/Makefile +2 -0
  74. data/ext/extconf.rb +1 -0
  75. data/lib/capricorn-client.rb +86 -0
  76. data/lib/capricorn-client/cli/applications.rb +256 -0
  77. data/lib/capricorn-client/cli/gems.rb +57 -0
  78. data/lib/capricorn-client/cli/machines.rb +9 -0
  79. data/lib/capricorn-client/helpers.rb +62 -0
  80. data/lib/capricorn.rb +5 -99
  81. data/lib/capricorn/driver.rb +86 -0
  82. data/lib/capricorn/recipes/apache-debian.rb +112 -0
  83. data/lib/capricorn/recipes/centos-plesk.rb +162 -0
  84. data/lib/capricorn/recipes/macports.rb +54 -0
  85. data/lib/capricorn/system_context.rb +49 -0
  86. data/lib/capricorn/version.rb +5 -0
  87. metadata +233 -74
  88. data/app_generators/engine/engine_generator.rb +0 -40
  89. data/app_generators/engine/templates/Gmfile +0 -20
  90. data/app_generators/engine/templates/MIT-LICENSE.txt +0 -20
  91. data/app_generators/engine/templates/README.rdoc +0 -7
  92. data/app_generators/engine/templates/config/initializers/rails_init.rb +0 -1
  93. data/app_generators/engine/templates/config/routes.rb +0 -2
  94. data/app_generators/engine/templates/gitignore +0 -9
  95. data/app_generators/engine/templates/init.rb +0 -1
  96. data/app_generators/engine/templates/lib/engine.rb +0 -4
  97. data/app_generators/engine/templates/rails/init.rb +0 -1
  98. data/app_generators/engine/templates/tasks/engine_tasks.rake +0 -4
  99. data/bin/capricorn +0 -20
  100. data/lib/capricorn/actor.rb +0 -23
  101. data/lib/capricorn/actor/actions.rb +0 -76
  102. data/lib/capricorn/actors/apache_actor.rb +0 -56
  103. data/lib/capricorn/actors/base_actor.rb +0 -335
  104. data/lib/capricorn/actors/host_file_actor.rb +0 -77
  105. data/lib/capricorn/actors/mysql_actor.rb +0 -20
  106. data/lib/capricorn/actors/passenger_actor.rb +0 -28
  107. data/lib/capricorn/actors/plesk_actor.rb +0 -228
  108. data/lib/capricorn/actors/sqlite3_actor.rb +0 -44
  109. data/lib/capricorn/app_runner.rb +0 -108
  110. data/lib/capricorn/apps/dev.rb +0 -15
  111. data/lib/capricorn/apps/engines.rb +0 -33
  112. data/lib/capricorn/apps/jobs.rb +0 -35
  113. data/lib/capricorn/apps/satellite.rb +0 -68
  114. data/lib/capricorn/apps/server.rb +0 -73
  115. data/lib/capricorn/client.rb +0 -48
  116. data/lib/capricorn/client/auth_token.rb +0 -98
  117. data/lib/capricorn/daemon.rb +0 -81
  118. data/lib/capricorn/exception_handler.rb +0 -79
  119. data/lib/capricorn/extentions/rubygems_plugin.rb +0 -27
  120. data/lib/capricorn/extentions/thor_extentions.rb +0 -32
  121. data/lib/capricorn/job_queue.rb +0 -203
  122. data/lib/capricorn/satellite.rb +0 -52
  123. data/lib/capricorn/satellite/actions.rb +0 -55
  124. data/lib/capricorn/satellite/dependency_loader.rb +0 -82
  125. data/lib/capricorn/satellite/persistence.rb +0 -50
  126. data/lib/capricorn/server.rb +0 -144
  127. data/lib/capricorn/server/daemon.rb +0 -83
  128. data/lib/capricorn/server/proxy.rb +0 -25
  129. data/lib/capricorn/server/security.rb +0 -120
  130. data/lib/capricorn/system.rb +0 -218
  131. data/lib/capricorn/system/config.rb +0 -49
  132. data/lib/capricorn/system/helper.rb +0 -21
  133. data/lib/capricorn/system/options.rb +0 -79
  134. data/lib/capricorn/system/process_user.rb +0 -73
  135. data/lib/capricorn/system/satellites.rb +0 -44
  136. data/lib/capricorn/system/shell.rb +0 -80
  137. data/lib/rubygems_plugin.rb +0 -1
  138. data/spec/actor/actions_spec.rb +0 -13
  139. data/spec/spec_helper.rb +0 -1
@@ -0,0 +1,45 @@
1
+ %%
2
+ %% Start application module
3
+ %%
4
+ %% File : capricorn.erl
5
+ %% Created: 2010-01-04
6
+ %%
7
+ %% @author simonmenke <simon.menke@gmail.com>
8
+ %% @copyright 2010 simonmenke
9
+ %%
10
+ %% @doc TODO make nice description
11
+ %%
12
+
13
+ -module(capricorn).
14
+ -author('simonmenke <simon.menke@gmail.com>').
15
+ -include("capricorn.hrl").
16
+
17
+ -export([start/0, stop/0, restart/0, reload/0]).
18
+
19
+ %% @spec start() -> ok
20
+ %% @doc Start the capricorn application
21
+ start() ->
22
+ application:start(capricorn).
23
+
24
+ %% @spec stop() -> ok
25
+ %% @doc Stop the capricorn application
26
+ stop() ->
27
+ application:stop(capricorn).
28
+
29
+ restart() ->
30
+ case stop() of
31
+ ok ->
32
+ start();
33
+ {error, {not_started,capricorn}} ->
34
+ start();
35
+ {error, Reason} ->
36
+ {error, Reason}
37
+ end.
38
+
39
+ reload() ->
40
+ case supervisor:terminate_child(cap_sup, cap_config) of
41
+ ok ->
42
+ supervisor:restart_child(cap_sup, cap_config);
43
+ {error, Reason} ->
44
+ {error, Reason}
45
+ end.
@@ -0,0 +1,36 @@
1
+ %%
2
+ %% Application module
3
+ %%
4
+ %% File : capricorn_app.erl
5
+ %% Created: 2010-01-04
6
+ %%
7
+ %% @author simonmenke <simon.menke@gmail.com>
8
+ %% @copyright 2010 simonmenke
9
+ %%
10
+ %% @doc TODO make nice description
11
+ %%
12
+
13
+ -module(capricorn_app).
14
+ -author('simonmenke <simon.menke@gmail.com>').
15
+ -include("capricorn.hrl").
16
+
17
+ -behaviour(application).
18
+
19
+ -export([start/2, stop/1]).
20
+
21
+ -spec start(_,_) -> {'error','already_started'} | {'ok',pid()} .
22
+ start(_Type, _) ->
23
+ NodeType = get_ini_node_type(),
24
+ cap_sup:start_link(NodeType).
25
+
26
+ stop(_) ->
27
+ cap_sup:stop(),
28
+ ok.
29
+
30
+ -spec get_ini_node_type() -> machine | cluster .
31
+ get_ini_node_type() ->
32
+ case init:get_argument(node_type) of
33
+ error -> machine;
34
+ {ok, [[]]} -> machine;
35
+ {ok, [[Type]]} -> list_to_atom(Type)
36
+ end.
@@ -0,0 +1,17 @@
1
+ {application, emq, [
2
+ {description, "Erlang Message Queue"},
3
+ {vsn, "0.1.0"},
4
+ {modules, [
5
+ emq,
6
+ emq_app,
7
+ emq_sup,
8
+ emq_pool,
9
+ emq_queue,
10
+ emq_status
11
+ ]},
12
+ {registered,[
13
+ emq_sup
14
+ ]},
15
+ {applications, [kernel, stdlib]},
16
+ {mod, {emq_app, []}}
17
+ ]}.
@@ -0,0 +1,261 @@
1
+ -module(emq).
2
+ -behaviour(gen_server).
3
+
4
+
5
+
6
+ -export([new/2]).
7
+ -export([push/3, push/4, push/5, push/6]).
8
+ -export([size/1, jobs/1, status/2, status/3]).
9
+
10
+ -export([start_link/1]).
11
+ -export([init/1, handle_call/3, handle_cast/2,
12
+ handle_info/2, terminate/2, code_change/3]).
13
+
14
+ -export([test/0]).
15
+
16
+
17
+
18
+ -record(state, {
19
+ name :: atom(),
20
+ queue :: pid(),
21
+ pool :: pid(),
22
+ status :: pid()
23
+ }).
24
+ % -type state() :: #state{} .
25
+
26
+
27
+
28
+ %%% External API
29
+ new(Name, Options) ->
30
+ emq_sup:start_queue(Name, Options).
31
+
32
+
33
+
34
+ push(QueueName, Id, Fun) ->
35
+ push(QueueName, Id, [], Fun).
36
+
37
+ push(QueueName, Id, Dependencies, Fun) ->
38
+ push(QueueName, Id, Dependencies, [], Fun).
39
+
40
+ push(QueueName, Id, Dependencies, Dependents, Fun) ->
41
+ push(QueueName, Id, Dependencies, Dependents, [], Fun).
42
+
43
+ push(QueueName, Id, Dependencies, Dependents, Callbacks, Fun) ->
44
+ {ok, Pid} = emq_sup:get_emq(QueueName),
45
+ gen_server:cast(Pid, {push, Id, Dependencies, Dependents, Callbacks, Fun}),
46
+ {ok, {QueueName, Id}}.
47
+
48
+
49
+
50
+ size(QueueName) ->
51
+ {ok, Pid} = emq_sup:get_queue(QueueName),
52
+ emq_queue:size(Pid).
53
+
54
+
55
+
56
+ jobs(QueueName) ->
57
+ {ok, Pid} = emq_sup:get_status(QueueName),
58
+ emq_status:get_all(Pid).
59
+
60
+
61
+
62
+ status(QueueName, Id) ->
63
+ {ok, Pid} = emq_sup:get_emq(QueueName),
64
+ gen_server:call(Pid, {status, Id}).
65
+
66
+ status(QueueName, Id, Status) ->
67
+ {ok, Pid} = emq_sup:get_emq(QueueName),
68
+ gen_server:cast(Pid, {status, Id, Status}).
69
+
70
+
71
+
72
+ %%% Start the server
73
+ -spec start_link([{size, pos_integer()}]) -> {ok, pid()} .
74
+ start_link(Options) ->
75
+ gen_server:start_link(?MODULE, Options, []).
76
+
77
+
78
+
79
+ %%% Initialize the server
80
+ init(Options) ->
81
+ Name = proplists:get_value(name, Options),
82
+ PoolSize = proplists:get_value(size, Options, 3),
83
+ {ok, Pool} = emq_pool:start_link(Name, PoolSize),
84
+ {ok, Queue} = emq_queue:start_link(Name),
85
+ {ok, Status} = emq_status:start_link(Name),
86
+
87
+ emq_sup:setup_process(Pool , Name, self(), Queue, Pool, Status),
88
+ emq_sup:setup_process(Queue, Name, self(), Queue, Pool, Status),
89
+ emq_sup:setup_process(Status, Name, self(), Queue, Pool, Status),
90
+
91
+ erlang:put('$emq_name', Name),
92
+ erlang:put('$emq', self()),
93
+ erlang:put('$emq_pool', Pool),
94
+ erlang:put('$emq_queue', Queue),
95
+ erlang:put('$emq_status', Status),
96
+
97
+ {ok, #state{ pool = Pool, queue = Queue, status = Status, name = Name }}.
98
+
99
+
100
+
101
+ %%% Handle call messages
102
+ handle_call({'$emq_internal_info'}, _From, State) ->
103
+ {reply, {ok, {
104
+ erlang:get('$emq_name'),
105
+ erlang:get('$emq_pool'),
106
+ erlang:get('$emq_queue'),
107
+ erlang:get('$emq_status')
108
+ }}, State};
109
+
110
+ handle_call({status, Id}, _From, State) ->
111
+ #state { status = Status } = State,
112
+ {reply, emq_status:get(Status, Id), State}.
113
+
114
+
115
+
116
+ %%% Handle cast messages
117
+ handle_cast({push, Id, Dependencies, Dependents, Callbacks, Fun}, State) ->
118
+ #state { queue = Queue } = State,
119
+ emq_queue:push(Queue, Id, Dependencies, Dependents, Callbacks, Fun),
120
+ do_try_exec(State),
121
+ {noreply, State};
122
+
123
+ handle_cast({status, Id, StatusObject}, State) ->
124
+ #state { status = Status } = State,
125
+ emq_status:put(Status, Id, StatusObject),
126
+ {noreply, State}.
127
+
128
+
129
+
130
+ %%% Handle generic messages
131
+ handle_info(kick, State) ->
132
+ do_try_exec(State),
133
+ {noreply, State};
134
+
135
+ handle_info({pool_did_job, Id}, State) ->
136
+ #state { queue = Queue } = State,
137
+ emq_queue:commit(Queue, Id),
138
+ do_try_exec(State),
139
+ {noreply, State}.
140
+
141
+
142
+
143
+ %%% Before stopping the server
144
+ terminate(_Reason, _State) ->
145
+ % stop children
146
+ ok.
147
+
148
+
149
+
150
+ %%% Code Changes
151
+ code_change(_OldVsn, State, _Extra) ->
152
+ {ok, State}.
153
+
154
+
155
+
156
+ %%% Internal API
157
+ do_try_exec(State) ->
158
+ #state { queue = Queue, pool = Pool } = State,
159
+ {ok, StatusPid} = emq_sup:get_status(local),
160
+ case emq_queue:reserve(Queue) of
161
+ {value, Id, Job, Callbacks} ->
162
+ R = emq_pool:do(Pool, fun({Id1, Job1, Callbacks1, StatusPid1}) ->
163
+ try
164
+ emq_status:put(StatusPid1, Id1, active),
165
+ case Job1 of
166
+ {Mod, Fun, Args} -> erlang:apply(Mod, Fun, Args);
167
+ {Fun, Args} -> erlang:apply(Fun, Args);
168
+ Fun -> Fun()
169
+ end
170
+ of
171
+ Result ->
172
+ lists:map(fun(Callback) ->
173
+ Callback(done, Result)
174
+ end, Callbacks1)
175
+ catch
176
+ error:Reason ->
177
+ lists:map(fun(Callback) ->
178
+ Callback(error, Reason)
179
+ end, Callbacks1),
180
+ error_logger:error_report({error, Id1, Reason, erlang:get_stacktrace()});
181
+ throw:Reason ->
182
+ lists:map(fun(Callback) ->
183
+ Callback(throw, Reason)
184
+ end, Callbacks1),
185
+ error_logger:error_report({throw, Id1, Reason});
186
+ exit:Reason ->
187
+ lists:map(fun(Callback) ->
188
+ Callback(exit, Reason)
189
+ end, Callbacks1),
190
+ error_logger:error_report({exit, Id1, Reason})
191
+ after
192
+ emq_status:delete(StatusPid1, Id1)
193
+ end,
194
+ Id1
195
+ end, {Id, Job, Callbacks, StatusPid}),
196
+ case R of
197
+ {error, no_workers} ->
198
+ emq_queue:rollback(Queue, Id);
199
+ ok ->
200
+ ignore
201
+ end;
202
+ {empty} -> ignore
203
+ end.
204
+
205
+
206
+
207
+ test() ->
208
+ application:start(emq),
209
+
210
+ emq:new(hello, [{size, 1}]),
211
+
212
+ emq:push(hello, hi, fun() ->
213
+ receive after 3000 -> io:format("hi ") end
214
+ end),
215
+ emq:push(hello, simon, [{hello, hi}], fun() ->
216
+ receive after 3000 -> io:format("simon!\n") end
217
+ end),
218
+
219
+ emq:push(hello, bye, fun() ->
220
+ receive after 3000 -> io:format("bye ") end
221
+ end),
222
+ emq:push(hello, simon, [{hello, bye}], fun() ->
223
+ receive after 3000 -> io:format("simon!\n") end
224
+ end),
225
+
226
+ % {ok, Id1} = emq:push(hello, make_ref(), fun() ->
227
+ % receive after 3000 -> io:format("hi ") end
228
+ % end),
229
+ % emq:push(hello, make_ref(), [Id1], fun() ->
230
+ % receive after 3000 -> io:format("simon!\n") end
231
+ % end),
232
+ %
233
+ % {ok, Id2} = emq:push(hello, make_ref(), fun() ->
234
+ % receive after 3000 -> io:format("hi ") end
235
+ % end),
236
+ % emq:push(hello, make_ref(), [Id2], fun() ->
237
+ % receive after 3000 -> io:format("simon!\n") end
238
+ % end),
239
+ %
240
+ % {ok, Id3} = emq:push(hello, make_ref(), fun() ->
241
+ % receive after 3000 -> io:format("hi ") end
242
+ % end),
243
+ % emq:push(hello, make_ref(), [Id3], fun() ->
244
+ % receive after 3000 -> io:format("simon!\n") end
245
+ % end),
246
+ %
247
+ % {ok, Id4} = emq:push(hello, make_ref(), fun() ->
248
+ % receive after 3000 -> io:format("hi ") end
249
+ % end),
250
+ % emq:push(hello, make_ref(), [Id4], fun() ->
251
+ % receive after 3000 -> io:format("simon!\n") end
252
+ % end),
253
+ %
254
+ % {ok, Id5} = emq:push(hello, make_ref(), fun() ->
255
+ % receive after 3000 -> io:format("hi ") end
256
+ % end),
257
+ % emq:push(hello, make_ref(), [Id5], fun() ->
258
+ % receive after 3000 -> io:format("simon!\n") end
259
+ % end),
260
+
261
+ ok.
@@ -0,0 +1,11 @@
1
+ -module(emq_app).
2
+ -behaviour(application).
3
+
4
+ -export([start/2, stop/1]).
5
+
6
+ start(_Type, _Args) ->
7
+ emq_sup:start_link().
8
+
9
+ stop(_) ->
10
+ emq_sup:stop(),
11
+ ok.
@@ -0,0 +1,178 @@
1
+ -module(emq_pool).
2
+ -behaviour(gen_server).
3
+
4
+
5
+
6
+ -export([size/1, size/2, active/1, idle/1, do/3]).
7
+
8
+ -export([start_link/2]).
9
+ -export([init/1, handle_call/3, handle_cast/2,
10
+ handle_info/2, terminate/2, code_change/3]).
11
+
12
+ -export([do_init_worker/2]).
13
+
14
+
15
+
16
+ -record(state, {
17
+ name :: atom(),
18
+ workers :: [pid()],
19
+ waiters :: [pid()],
20
+ size :: pos_integer(),
21
+ owner :: pid()
22
+ }).
23
+ -type state() :: #state{} .
24
+
25
+
26
+
27
+ %%% External API
28
+ size(Pid) ->
29
+ gen_server:call(Pid, {size}).
30
+
31
+
32
+
33
+ size(Pid, Size) ->
34
+ gen_server:call(Pid, {size, Size}).
35
+
36
+
37
+
38
+ active(Pid) ->
39
+ gen_server:call(Pid, {active}).
40
+
41
+
42
+
43
+ idle(Pid) ->
44
+ gen_server:call(Pid, {idle}).
45
+
46
+
47
+
48
+ do(Pid, Fun, Ctx) ->
49
+ gen_server:call(Pid, {do, Fun, Ctx}).
50
+
51
+
52
+
53
+ %%% Start the server
54
+ -spec start_link(atom(), pos_integer()) -> {ok, pid()} .
55
+ start_link(Name, Size) ->
56
+ gen_server:start_link(?MODULE, {Name, Size, self()}, []).
57
+
58
+
59
+
60
+ %%% Initialize the server
61
+ -spec init({atom(), pos_integer(), pid()}) -> {ok, state()} .
62
+ init({Name, Size, Owner}) ->
63
+ {ok, #state{ waiters=[], workers=[], size=Size, owner=Owner, name=Name }}.
64
+
65
+
66
+
67
+ %%% Handle call messages
68
+ handle_call({setup_process, Name, Emq, Queue, Pool, Status}, _From, State) ->
69
+ erlang:put('$emq_name', Name),
70
+ erlang:put('$emq', Emq),
71
+ erlang:put('$emq_pool', Pool),
72
+ erlang:put('$emq_queue', Queue),
73
+ erlang:put('$emq_status', Status),
74
+ {reply, ok, State};
75
+
76
+ handle_call({size, Size}, _From, State) ->
77
+ {reply, ok, State#state{ size=Size }};
78
+
79
+ handle_call({size}, _From, State) ->
80
+ {reply, State#state.size, State};
81
+
82
+ handle_call({active}, _From, State) ->
83
+ {reply, erlang:length(State#state.workers), State};
84
+
85
+ handle_call({idle}, _From, State) ->
86
+ {reply, erlang:length(State#state.waiters), State};
87
+
88
+ handle_call({do, Fun, Ctx}, _From, State) ->
89
+ case do_get_worker(State) of
90
+ {State1, Worker} ->
91
+ Worker ! {exec, Fun, Ctx},
92
+ {reply, ok, State1};
93
+ {State1} ->
94
+ {reply, {error, no_workers}, State1}
95
+ end.
96
+
97
+
98
+
99
+ %%% Handle cast messages
100
+ handle_cast(_Msg, State) ->
101
+ {noreply, State}.
102
+
103
+
104
+ %%% Handle generic messages
105
+ handle_info({done, Worker, Ctx}, State) ->
106
+ #state { waiters = Waiters, workers = Workers, owner = Owner } = State,
107
+ Owner ! {pool_did_job, Ctx},
108
+ {noreply, State#state{
109
+ waiters = [Worker|Waiters],
110
+ workers = lists:delete(Worker, Workers)
111
+ }};
112
+
113
+ handle_info({'DOWN', _, process, Worker, Reason}, State) ->
114
+ error_logger:error_msg("Worker Exited unexpectedly~n", []),
115
+ error_logger:error_report(Reason),
116
+ #state { waiters = Waiters, workers = Workers } = State,
117
+ {noreply, State#state{
118
+ waiters = lists:delete(Worker, Waiters),
119
+ workers = lists:delete(Worker, Workers)
120
+ }}.
121
+
122
+
123
+ %%% Before stopping the server
124
+ terminate(_Reason, _State) ->
125
+ ok.
126
+
127
+
128
+ %%% Code Changes
129
+ code_change(_OldVsn, State, _Extra) ->
130
+ [Pid1 ! stop || Pid1 <- State#state.workers],
131
+ [Pid2 ! stop || Pid2 <- State#state.waiters],
132
+ {ok, State}.
133
+
134
+
135
+ %%% Internal API
136
+ -spec do_get_worker(state()) -> {state(), pid()} | {state()} .
137
+ do_get_worker(State) ->
138
+ #state { size = Size, workers = Workers, waiters = Waiters, owner = Owner } = State,
139
+ if
140
+ length(Waiters) > 0 ->
141
+ [Pid | Waiters2] = Waiters,
142
+ Workers2 = [Pid | Workers],
143
+ {State#state { workers=Workers2, waiters=Waiters2 }, Pid};
144
+ length(Workers) < Size ->
145
+ Pid = spawn(?MODULE, do_init_worker, [self(), Owner]),
146
+ erlang:monitor(process, Pid),
147
+ Pid ! go,
148
+ {State#state { workers=[Pid | Workers] }, Pid};
149
+ true ->
150
+ {State}
151
+ end.
152
+
153
+ do_init_worker(Pool, Owner) ->
154
+ erlang:monitor(process, Pool),
155
+ receive
156
+ go ->
157
+ do_loop_worker(Pool, Owner);
158
+ stop ->
159
+ erlang:exit(normal);
160
+ {'DOWN', _, process, Pool, _} ->
161
+ erlang:exit(normal)
162
+ after 300000 ->
163
+ erlang:exit(normal)
164
+ end.
165
+
166
+ do_loop_worker(Pool, Owner) ->
167
+ receive
168
+ stop ->
169
+ erlang:exit(normal);
170
+ {'DOWN', _, process, Pool, _} ->
171
+ erlang:exit(normal);
172
+ {exec, Fun, Ctx1} ->
173
+ Ctx2 = erlang:apply(Fun, [Ctx1]),
174
+ Pool ! {done, self(), Ctx2},
175
+ do_loop_worker(Pool, Owner)
176
+ after 300000 ->
177
+ erlang:exit(normal)
178
+ end.