Skip to content

Commit c4139ad

Browse files
committed
fix #278: ref counting and error handling cleanup during recycle
1 parent 45eeb88 commit c4139ad

6 files changed

+92
-24
lines changed

Diff for: src/iisnode/cnodeapplication.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ HRESULT CNodeApplication::Dispatch(IHttpContext* context, IHttpEventProvider* pP
8686
// CProtocolBridge::FinalizeResponseCore, possibly after several context switches
8787
(*ctx)->IncreasePendingAsyncOperationCount();
8888

89-
CheckError(this->processManager->Dispatch(*ctx));
89+
// At this point ownership of the request is handed over to Dispach below, including error handling.
90+
// Therefore we don't propagate any errors up the stack.
91+
this->processManager->Dispatch(*ctx);
9092

9193
return S_OK;
9294

Diff for: src/iisnode/cnodehttpmodule.cpp

+68-13
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnSendResponse(IN IHttpContext* pHt
1414
if (NULL != ctx && ctx->GetIsUpgrade() && !ctx->GetOpaqueFlagSet())
1515
{
1616
// Set opaque mode in HTTP.SYS to enable exchanging raw bytes.
17-
1817

1918
pProvider->SetFlags(flags | HTTP_SEND_RESPONSE_FLAG_OPAQUE);
2019
ctx->SetOpaqueFlag();
@@ -37,25 +36,64 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnExecuteRequestHandler(
3736
this->applicationManager->GetEventProvider()->Log(L"iisnode received a new http request", WINEVENT_LEVEL_INFO);
3837

3938
CheckError(this->applicationManager->Dispatch(pHttpContext, pProvider, &ctx));
39+
this->applicationManager->GetEventProvider()->Log(L"iisnode dispatched new http request", WINEVENT_LEVEL_INFO, ctx->GetActivityId());
4040
ASYNC_CONTEXT* async = ctx->GetAsyncContext();
4141
async->RunSynchronousContinuations();
4242

43+
REQUEST_NOTIFICATION_STATUS result;
4344
if (0 == ctx->DecreasePendingAsyncOperationCount()) // decreases ref count set to 1 in the ctor of CNodeHttpStoredContext
4445
{
45-
return ctx->GetRequestNotificationStatus();
46+
result = ctx->GetRequestNotificationStatus();
4647
}
4748
else
4849
{
49-
return RQ_NOTIFICATION_PENDING;
50+
result = RQ_NOTIFICATION_PENDING;
5051
}
5152

53+
switch (result)
54+
{
55+
default:
56+
this->applicationManager->GetEventProvider()->Log(
57+
L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler",
58+
WINEVENT_LEVEL_VERBOSE,
59+
ctx->GetActivityId());
60+
break;
61+
case RQ_NOTIFICATION_CONTINUE:
62+
this->applicationManager->GetEventProvider()->Log(
63+
L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_CONTINUE",
64+
WINEVENT_LEVEL_VERBOSE,
65+
ctx->GetActivityId());
66+
break;
67+
case RQ_NOTIFICATION_FINISH_REQUEST:
68+
this->applicationManager->GetEventProvider()->Log(
69+
L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_FINISH_REQUEST",
70+
WINEVENT_LEVEL_VERBOSE,
71+
ctx->GetActivityId());
72+
break;
73+
case RQ_NOTIFICATION_PENDING:
74+
this->applicationManager->GetEventProvider()->Log(
75+
L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_PENDING",
76+
WINEVENT_LEVEL_VERBOSE,
77+
ctx->GetActivityId());
78+
break;
79+
};
80+
81+
return result;
82+
5283
Error:
5384

5485
CNodeEventProvider* log = this->applicationManager->GetEventProvider();
5586

5687
if (log)
5788
{
58-
log->Log(L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO);
89+
if (ctx)
90+
{
91+
log->Log(L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO, ctx->GetActivityId());
92+
}
93+
else
94+
{
95+
log->Log(L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO);
96+
}
5997
}
6098

6199
if (ERROR_NOT_ENOUGH_QUOTA == hr)
@@ -181,22 +219,39 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnAsyncCompletion(
181219
async->RunSynchronousContinuations();
182220
}
183221

184-
if (0 == ctx->DecreasePendingAsyncOperationCount()) // decreases ref count increased on entering OnAsyncCompletion
222+
ctx->DecreasePendingAsyncOperationCount();
223+
224+
REQUEST_NOTIFICATION_STATUS result = ctx->GetRequestNotificationStatus();
225+
226+
switch (result)
185227
{
228+
default:
186229
this->applicationManager->GetEventProvider()->Log(
187-
L"iisnode leaves CNodeHttpModule::OnAsyncCompletion and completes the request",
230+
L"iisnode leaves CNodeHttpModule::OnAsyncCompletion",
188231
WINEVENT_LEVEL_VERBOSE,
189232
ctx->GetActivityId());
190-
return ctx->GetRequestNotificationStatus();
191-
}
192-
else
193-
{
233+
break;
234+
case RQ_NOTIFICATION_CONTINUE:
194235
this->applicationManager->GetEventProvider()->Log(
195-
L"iisnode leaves CNodeHttpModule::OnAsyncCompletion and continues the request",
236+
L"iisnode leaves CNodeHttpModule::OnAsyncCompletion with RQ_NOTIFICATION_CONTINUE",
196237
WINEVENT_LEVEL_VERBOSE,
197238
ctx->GetActivityId());
198-
return RQ_NOTIFICATION_PENDING;
199-
}
239+
break;
240+
case RQ_NOTIFICATION_FINISH_REQUEST:
241+
this->applicationManager->GetEventProvider()->Log(
242+
L"iisnode leaves CNodeHttpModule::OnAsyncCompletion with RQ_NOTIFICATION_FINISH_REQUEST",
243+
WINEVENT_LEVEL_VERBOSE,
244+
ctx->GetActivityId());
245+
break;
246+
case RQ_NOTIFICATION_PENDING:
247+
this->applicationManager->GetEventProvider()->Log(
248+
L"iisnode leaves CNodeHttpModule::OnAsyncCompletion with RQ_NOTIFICATION_PENDING",
249+
WINEVENT_LEVEL_VERBOSE,
250+
ctx->GetActivityId());
251+
break;
252+
};
253+
254+
return result;
200255
}
201256

202257
return RQ_NOTIFICATION_CONTINUE;

Diff for: src/iisnode/cnodehttpstoredcontext.cpp

+11-9
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,10 @@ CNodeHttpStoredContext::CNodeHttpStoredContext(CNodeApplication* nodeApplication
1515
this->responseChunk.FromMemory.pBuffer = NULL;
1616

1717
RtlZeroMemory(&this->asyncContext, sizeof(ASYNC_CONTEXT));
18-
if (NULL != (tctx = context->GetTraceContext()) && NULL != (pguid = tctx->GetTraceActivityId()))
19-
{
20-
memcpy(&this->activityId, pguid, sizeof GUID);
21-
}
22-
else
23-
{
24-
CoCreateGuid(&this->activityId);
25-
}
18+
CoCreateGuid(&this->activityId);
2619

2720
this->asyncContext.data = this;
21+
this->eventProvider = nodeApplication->GetApplicationManager()->GetEventProvider();
2822
}
2923

3024
CNodeHttpStoredContext::~CNodeHttpStoredContext()
@@ -287,6 +281,10 @@ GUID* CNodeHttpStoredContext::GetActivityId()
287281

288282
long CNodeHttpStoredContext::IncreasePendingAsyncOperationCount()
289283
{
284+
this->eventProvider->Log(
285+
L"iisnode increases pending async operation count",
286+
WINEVENT_LEVEL_VERBOSE,
287+
this->GetActivityId());
290288
if (this->requestPumpStarted)
291289
{
292290
return InterlockedIncrement(&this->upgradeContext->pendingAsyncOperationCount);
@@ -299,6 +297,10 @@ long CNodeHttpStoredContext::IncreasePendingAsyncOperationCount()
299297

300298
long CNodeHttpStoredContext::DecreasePendingAsyncOperationCount()
301299
{
300+
this->eventProvider->Log(
301+
L"iisnode decreases pending async operation count",
302+
WINEVENT_LEVEL_VERBOSE,
303+
this->GetActivityId());
302304
if (this->requestPumpStarted)
303305
{
304306
return InterlockedDecrement(&this->upgradeContext->pendingAsyncOperationCount);
@@ -456,4 +458,4 @@ void CNodeHttpStoredContext::SetBytesCompleted(DWORD bytesCompleted)
456458
void CNodeHttpStoredContext::SetContinueSynchronously(BOOL continueSynchronously)
457459
{
458460
this->asyncContext.continueSynchronously = continueSynchronously;
459-
}
461+
}

Diff for: src/iisnode/cnodehttpstoredcontext.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class CNodeHttpStoredContext : public IHttpStoredContext
2424
BOOL isChunked;
2525
HRESULT result;
2626
REQUEST_NOTIFICATION_STATUS requestNotificationStatus;
27-
long pendingAsyncOperationCount;
27+
long volatile pendingAsyncOperationCount;
2828
PCSTR targetUrl;
2929
DWORD targetUrlLength;
3030
IHttpContext* childContext;
@@ -39,6 +39,7 @@ class CNodeHttpStoredContext : public IHttpStoredContext
3939
FILETIME startTime;
4040
HTTP_DATA_CHUNK responseChunk;
4141
DWORD responseChunkBufferSize;
42+
CNodeEventProvider* eventProvider;
4243

4344
public:
4445

Diff for: src/iisnode/cnodeprocessmanager.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,18 @@ HRESULT CNodeProcessManager::Dispatch(CNodeHttpStoredContext* request)
145145
}
146146

147147
CheckError(this->processes[processToUse]->AcceptRequest(request));
148+
request = NULL;
148149
}
149150

150151
LEAVE_SRW_EXCLUSIVE(this->srwlock)
151152
}
152153
}
154+
155+
if (request)
156+
{
157+
this->GetEventProvider()->Log(L"iisnode failed to accept a request beacuse the application is recycling", WINEVENT_LEVEL_ERROR, request->GetActivityId());
158+
CProtocolBridge::SendEmptyResponse(request, 503, _T("Service Unavailable"), IISNODE_ERROR_APPLICATION_IS_RECYCLING);
159+
}
153160

154161
this->DecRef(); // incremented at the beginning of this method
155162

Diff for: src/iisnode/errors.h

+1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
#define IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION 1031L
1111
#define IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_OVERRIDE 1032L
1212
#define IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_FROM_ENVIRONMENT 1033L
13+
#define IISNODE_ERROR_APPLICATION_IS_RECYCLING 1034L
1314

1415
#endif

0 commit comments

Comments
 (0)