Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Add command to kill workers after they're checked back in, and fix bugs

Extend the 'status' to check the number of monitors poolboy has on
processes that have checked out workers. When a process dies after being
checked back in, poolboy zeroes out the list of monitors for some reason.
  • Loading branch information...
commit eacf28f164fc7a72af3d33a83ccc4e9c71019187 1 parent c2ba14c
Andrew Thompson authored January 21, 2012
4  src/poolboy.erl
@@ -231,7 +231,7 @@ handle_sync_event(stop, _From, _StateName,State) ->
231 231
     {stop, normal, ok, State};
232 232
 handle_sync_event(status, _From, StateName, State) ->
233 233
     {reply, {StateName, queue:len(State#state.workers),
234  
-            State#state.overflow},
  234
+            State#state.overflow, length(State#state.monitors)},
235 235
         StateName, State};
236 236
 handle_sync_event(_Event, _From, StateName, State) ->
237 237
     Reply = {error, invalid_message},
@@ -253,7 +253,7 @@ handle_info({'EXIT', Pid, _}, StateName, State) ->
253 253
            worker_init = InitFun} = State,
254 254
     Monitors = case lists:keytake(Pid, 1, State#state.monitors) of
255 255
         {value, {_, Ref}, Left} -> erlang:demonitor(Ref), Left;
256  
-        false -> []
  256
+        false -> State#state.monitors
257 257
     end,
258 258
     case StateName of
259 259
         ready ->
28  test/poolboy_eqc.erl
@@ -34,8 +34,8 @@ command(S) ->
34 34
 			%% checkout shrinks to checkout_nonblock so we can simplify counterexamples
35 35
 			[{call, ?MODULE, ?SHRINK(checkout_block, [checkout_nonblock]), [S#state.pid]} || S#state.pid /= undefined] ++
36 36
 			[{call, ?MODULE, checkin, [S#state.pid, elements(S#state.checked_out)]} || S#state.pid /= undefined, S#state.checked_out /= []] ++
37  
-			[{call, ?MODULE, kill_worker, [elements(S#state.checked_out)]} || S#state.pid /= undefined, S#state.checked_out /= []
38  
-			]
  37
+			[{call, ?MODULE, kill_worker, [elements(S#state.checked_out)]} || S#state.pid /= undefined, S#state.checked_out /= []] ++
  38
+			[{call, ?MODULE, kill_idle_worker, [S#state.pid]} || S#state.pid /= undefined]
39 39
 	).
40 40
 
41 41
 make_args(_S, Size, Overflow) ->
@@ -64,6 +64,17 @@ kill_worker(Worker) ->
64 64
 	exit(Worker, kill),
65 65
 	timer:sleep(1).
66 66
 
  67
+kill_idle_worker(Pool) ->
  68
+	Pid = poolboy:checkout(Pool, false),
  69
+	case Pid of
  70
+		_ when is_pid(Pid) ->
  71
+			poolboy:checkin(Pool, Pid),
  72
+			kill_worker(Pid);
  73
+		_ ->
  74
+			timer:sleep(1),
  75
+			kill_idle_worker(Pool)
  76
+	end.
  77
+
67 78
 precondition(S,{call,_,start_poolboy,_}) ->
68 79
 	%% only start new pool when old one is stopped
69 80
   S#state.pid == undefined;
@@ -74,6 +85,8 @@ precondition(S, {call, _, checkin, [_Pool, Pid]}) ->
74 85
 	lists:member(Pid, S#state.checked_out);
75 86
 precondition(S, {call, _, kill_worker, [Pid]}) ->
76 87
 	lists:member(Pid, S#state.checked_out);
  88
+precondition(S,{call,_,kill_idle_worker,[_Pool]}) ->
  89
+	length(S#state.checked_out) < S#state.size;
77 90
 precondition(_S,{call,_,_,_}) ->
78 91
 	true.
79 92
 
@@ -89,13 +102,14 @@ dynamic_precondition(S = #state{pid=Pid},_) when Pid /= undefined ->
89 102
 
90 103
 	Workers = max(0, S#state.size - length(S#state.checked_out)),
91 104
 	OverFlow = max(0, length(S#state.checked_out) - S#state.size),
  105
+	Monitors = length(S#state.checked_out),
92 106
 
93 107
 	RealStatus = gen_fsm:sync_send_all_state_event(Pid, status),
94  
-	case RealStatus == {State, Workers, OverFlow} of
  108
+	case RealStatus == {State, Workers, OverFlow, Monitors} of
95 109
 		true ->
96 110
 			true;
97 111
 		_ ->
98  
-			exit({wrong_state, RealStatus, {State, Workers, OverFlow}})
  112
+			exit({wrong_state, RealStatus, {State, Workers, OverFlow, Monitors}})
99 113
 	end;
100 114
 dynamic_precondition(_,_) ->
101 115
 	true.
@@ -145,9 +159,9 @@ next_state(S,V,{call,_,checkout_nonblock,_}) ->
145 159
 next_state(S,_V,{call, _, checkin, [_Pool, Worker]}) ->
146 160
 	S#state{checked_out=S#state.checked_out -- [Worker]};
147 161
 next_state(S,_V,{call, _, kill_worker, [Worker]}) ->
148  
-	S#state{checked_out=S#state.checked_out -- [Worker]}.
149  
-
150  
-
  162
+	S#state{checked_out=S#state.checked_out -- [Worker]};
  163
+next_state(S,_V,{call, _, kill_idle_worker, [_Pool]}) ->
  164
+	S.
151 165
 
152 166
 prop_sequential() ->
153 167
 		?FORALL(Cmds,commands(?MODULE),

0 notes on commit eacf28f

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