2
2
3
3
CNodeProcessManager::CNodeProcessManager (CNodeApplication* application, IHttpContext* context)
4
4
: application(application), processes(NULL ), currentProcess(0 ), isClosing(FALSE ),
5
- refCount(1 )
5
+ refCount(1 ), gracefulShutdownProcessCount( 0 )
6
6
{
7
7
if (this ->GetApplication ()->IsDebugMode ())
8
8
{
@@ -18,6 +18,7 @@ CNodeProcessManager::CNodeProcessManager(CNodeApplication* application, IHttpCon
18
18
19
19
this ->gracefulShutdownTimeout = CModuleConfiguration::GetGracefulShutdownTimeout (context);
20
20
InitializeSRWLock (&this ->srwlock );
21
+ this ->gracefulShutdownDrainHandle = CreateEvent (NULL , TRUE , TRUE , NULL );
21
22
}
22
23
23
24
CNodeProcessManager::~CNodeProcessManager ()
@@ -40,6 +41,9 @@ void CNodeProcessManager::Cleanup()
40
41
delete[] this ->processes ;
41
42
this ->processes = NULL ;
42
43
}
44
+
45
+ CloseHandle (this ->gracefulShutdownDrainHandle );
46
+ this ->gracefulShutdownDrainHandle = NULL ;
43
47
}
44
48
45
49
CNodeApplication* CNodeProcessManager::GetApplication ()
@@ -203,6 +207,12 @@ HRESULT CNodeProcessManager::RecycleProcess(CNodeProcess* process)
203
207
204
208
this ->processes [i] = NULL ;
205
209
210
+ // prevent the CNodeProcessManager from recycling until all CNodeProcesses that died finished graceful shutdown
211
+ if (1L == InterlockedIncrement (&this ->gracefulShutdownProcessCount ))
212
+ {
213
+ ResetEvent (this ->gracefulShutdownDrainHandle );
214
+ }
215
+
206
216
gracefulRecycle = TRUE ;
207
217
}
208
218
}
@@ -237,6 +247,11 @@ HRESULT CNodeProcessManager::RecycleProcess(CNodeProcess* process)
237
247
delete args;
238
248
}
239
249
250
+ if (0L == InterlockedDecrement (&this ->gracefulShutdownProcessCount ))
251
+ {
252
+ SetEvent (this ->gracefulShutdownDrainHandle );
253
+ }
254
+
240
255
return hr;
241
256
}
242
257
@@ -245,48 +260,25 @@ HRESULT CNodeProcessManager::Recycle()
245
260
HRESULT hr;
246
261
HANDLE recycler;
247
262
ProcessRecycleArgs* args = NULL ;
248
- BOOL deleteApplication = FALSE ;
249
263
250
264
ENTER_SRW_EXCLUSIVE (this ->srwlock )
251
265
252
266
this ->isClosing = TRUE ;
253
267
254
- BOOL hasActiveProcess = FALSE ;
255
- for (int i = 0 ; i < this ->processCount ; i++)
256
- {
257
- if (this ->processes [i])
258
- {
259
- hasActiveProcess = TRUE ;
260
- break ;
261
- }
262
- }
263
-
264
- if (hasActiveProcess)
265
- {
266
- // perform actual recycling on a diffrent thread to free up the file watcher thread
268
+ // perform actual recycling on a diffrent thread to free up the file watcher thread
267
269
268
- ErrorIf (NULL == (args = new ProcessRecycleArgs), ERROR_NOT_ENOUGH_MEMORY);
269
- args->count = this ->processCount ;
270
- args->process = NULL ;
271
- args->processes = this ->processes ;
272
- args->processManager = this ;
273
- args->disposeApplication = TRUE ;
274
- args->disposeProcess = FALSE ;
275
- ErrorIf ((HANDLE)-1L == (recycler = (HANDLE) _beginthreadex (NULL , 0 , CNodeProcessManager::GracefulShutdown, args, 0 , NULL )), ERROR_NOT_ENOUGH_MEMORY);
276
- CloseHandle (recycler);
277
- }
278
- else
279
- {
280
- deleteApplication = TRUE ;
281
- }
270
+ ErrorIf (NULL == (args = new ProcessRecycleArgs), ERROR_NOT_ENOUGH_MEMORY);
271
+ args->count = this ->processCount ;
272
+ args->process = NULL ;
273
+ args->processes = this ->processes ;
274
+ args->processManager = this ;
275
+ args->disposeApplication = TRUE ;
276
+ args->disposeProcess = FALSE ;
277
+ ErrorIf ((HANDLE)-1L == (recycler = (HANDLE) _beginthreadex (NULL , 0 , CNodeProcessManager::GracefulShutdown, args, 0 , NULL )), ERROR_NOT_ENOUGH_MEMORY);
278
+ CloseHandle (recycler);
282
279
283
280
LEAVE_SRW_EXCLUSIVE (this ->srwlock )
284
281
285
- if (deleteApplication)
286
- {
287
- delete this ->GetApplication ();
288
- }
289
-
290
282
return S_OK;
291
283
Error:
292
284
@@ -309,7 +301,7 @@ unsigned int CNodeProcessManager::GracefulShutdown(void* arg)
309
301
310
302
// drain active requests
311
303
312
- ErrorIf (NULL == (drainHandles = new HANDLE[args->count ]), ERROR_NOT_ENOUGH_MEMORY);
304
+ ErrorIf (NULL == (drainHandles = new HANDLE[args->count + 1 ]), ERROR_NOT_ENOUGH_MEMORY);
313
305
RtlZeroMemory (drainHandles, args->count * sizeof HANDLE);
314
306
for (int i = 0 ; i < args->count ; i++)
315
307
{
@@ -320,12 +312,24 @@ unsigned int CNodeProcessManager::GracefulShutdown(void* arg)
320
312
drainHandleCount++;
321
313
}
322
314
}
315
+
316
+ if (args->disposeApplication )
317
+ {
318
+ // prevent the application from exiting until pending graceful shutdown of died CNodeProcesses has finished
319
+ drainHandles[drainHandleCount++] = args->processManager ->gracefulShutdownDrainHandle ;
320
+ }
323
321
324
322
if (args->processManager ->gracefulShutdownTimeout > 0 )
325
323
{
326
324
WaitForMultipleObjects (drainHandleCount, drainHandles, TRUE , args->processManager ->gracefulShutdownTimeout );
327
325
}
328
326
327
+ if (args->disposeApplication )
328
+ {
329
+ // do not close the gracefulShutdownDrainHandle as it is owned by CNodeProcessManager
330
+ drainHandleCount--;
331
+ }
332
+
329
333
for (int i = 0 ; i < drainHandleCount; i++)
330
334
{
331
335
CloseHandle (drainHandles[i]);
@@ -346,6 +350,11 @@ unsigned int CNodeProcessManager::GracefulShutdown(void* arg)
346
350
// this is the single process recycling code path (e.g. node.exe died)
347
351
348
352
delete args->processes [0 ];
353
+ if (0L == InterlockedDecrement (&args->processManager ->gracefulShutdownProcessCount ))
354
+ {
355
+ // release recycle of CNodeApplication that may be running concurrently
356
+ SetEvent (args->processManager ->gracefulShutdownDrainHandle );
357
+ }
349
358
}
350
359
351
360
delete args;
@@ -356,6 +365,15 @@ unsigned int CNodeProcessManager::GracefulShutdown(void* arg)
356
365
357
366
if (args)
358
367
{
368
+ if (args->disposeProcess )
369
+ {
370
+ if (0L == InterlockedDecrement (&args->processManager ->gracefulShutdownProcessCount ))
371
+ {
372
+ // release recycle of CNodeApplication that may be running concurrently
373
+ SetEvent (args->processManager ->gracefulShutdownDrainHandle );
374
+ }
375
+ }
376
+
359
377
delete args;
360
378
args = NULL ;
361
379
}
0 commit comments