Skip to content

Commit a3f0db9

Browse files
committed
fix #274: av during graceful process recycle
1 parent ab3f33f commit a3f0db9

File tree

2 files changed

+55
-35
lines changed

2 files changed

+55
-35
lines changed

Diff for: src/iisnode/cnodeprocessmanager.cpp

+53-35
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
CNodeProcessManager::CNodeProcessManager(CNodeApplication* application, IHttpContext* context)
44
: application(application), processes(NULL), currentProcess(0), isClosing(FALSE),
5-
refCount(1)
5+
refCount(1), gracefulShutdownProcessCount(0)
66
{
77
if (this->GetApplication()->IsDebugMode())
88
{
@@ -18,6 +18,7 @@ CNodeProcessManager::CNodeProcessManager(CNodeApplication* application, IHttpCon
1818

1919
this->gracefulShutdownTimeout = CModuleConfiguration::GetGracefulShutdownTimeout(context);
2020
InitializeSRWLock(&this->srwlock);
21+
this->gracefulShutdownDrainHandle = CreateEvent(NULL, TRUE, TRUE, NULL);
2122
}
2223

2324
CNodeProcessManager::~CNodeProcessManager()
@@ -40,6 +41,9 @@ void CNodeProcessManager::Cleanup()
4041
delete[] this->processes;
4142
this->processes = NULL;
4243
}
44+
45+
CloseHandle(this->gracefulShutdownDrainHandle);
46+
this->gracefulShutdownDrainHandle = NULL;
4347
}
4448

4549
CNodeApplication* CNodeProcessManager::GetApplication()
@@ -203,6 +207,12 @@ HRESULT CNodeProcessManager::RecycleProcess(CNodeProcess* process)
203207

204208
this->processes[i] = NULL;
205209

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+
206216
gracefulRecycle = TRUE;
207217
}
208218
}
@@ -237,6 +247,11 @@ HRESULT CNodeProcessManager::RecycleProcess(CNodeProcess* process)
237247
delete args;
238248
}
239249

250+
if (0L == InterlockedDecrement(&this->gracefulShutdownProcessCount))
251+
{
252+
SetEvent(this->gracefulShutdownDrainHandle);
253+
}
254+
240255
return hr;
241256
}
242257

@@ -245,48 +260,25 @@ HRESULT CNodeProcessManager::Recycle()
245260
HRESULT hr;
246261
HANDLE recycler;
247262
ProcessRecycleArgs* args = NULL;
248-
BOOL deleteApplication = FALSE;
249263

250264
ENTER_SRW_EXCLUSIVE(this->srwlock)
251265

252266
this->isClosing = TRUE;
253267

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
267269

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);
282279

283280
LEAVE_SRW_EXCLUSIVE(this->srwlock)
284281

285-
if (deleteApplication)
286-
{
287-
delete this->GetApplication();
288-
}
289-
290282
return S_OK;
291283
Error:
292284

@@ -309,7 +301,7 @@ unsigned int CNodeProcessManager::GracefulShutdown(void* arg)
309301

310302
// drain active requests
311303

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);
313305
RtlZeroMemory(drainHandles, args->count * sizeof HANDLE);
314306
for (int i = 0; i < args->count; i++)
315307
{
@@ -320,12 +312,24 @@ unsigned int CNodeProcessManager::GracefulShutdown(void* arg)
320312
drainHandleCount++;
321313
}
322314
}
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+
}
323321

324322
if (args->processManager->gracefulShutdownTimeout > 0)
325323
{
326324
WaitForMultipleObjects(drainHandleCount, drainHandles, TRUE, args->processManager->gracefulShutdownTimeout);
327325
}
328326

327+
if (args->disposeApplication)
328+
{
329+
// do not close the gracefulShutdownDrainHandle as it is owned by CNodeProcessManager
330+
drainHandleCount--;
331+
}
332+
329333
for (int i = 0; i < drainHandleCount; i++)
330334
{
331335
CloseHandle(drainHandles[i]);
@@ -346,6 +350,11 @@ unsigned int CNodeProcessManager::GracefulShutdown(void* arg)
346350
// this is the single process recycling code path (e.g. node.exe died)
347351

348352
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+
}
349358
}
350359

351360
delete args;
@@ -356,6 +365,15 @@ unsigned int CNodeProcessManager::GracefulShutdown(void* arg)
356365

357366
if (args)
358367
{
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+
359377
delete args;
360378
args = NULL;
361379
}

Diff for: src/iisnode/cnodeprocessmanager.h

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class CNodeProcessManager
2828
BOOL isClosing;
2929
long refCount;
3030
CNodeEventProvider* eventProvider;
31+
HANDLE gracefulShutdownDrainHandle;
32+
long gracefulShutdownProcessCount;
3133

3234
HRESULT AddProcess(int ordinal, IHttpContext* context);
3335
static unsigned int WINAPI GracefulShutdown(void* arg);

0 commit comments

Comments
 (0)