in Source/HTTP/httpcall.cpp [382:477]
void retry_http_call_until_done(
_In_ HC_UNIQUE_PTR<retry_context> retryContext
)
{
auto httpSingleton = get_http_singleton();
if (nullptr == httpSingleton)
{
HC_TRACE_WARNING(HTTPCLIENT, "Http call after HCCleanup was called. Aborting call.");
XAsyncComplete(retryContext->outerAsyncBlock, E_HC_NOT_INITIALISED, 0);
return;
}
auto requestStartTime = chrono_clock_t::now();
HC_CALL* call = retryContext->call->get();
if (call->retryIterationNumber == 0)
{
call->firstRequestStartTime = requestStartTime;
}
call->retryIterationNumber++;
if (call->traceCall) { HC_TRACE_INFORMATION(HTTPCLIENT, "HCHttpCallPerformExecute [ID %llu] Iteration %d", TO_ULL(call->id), call->retryIterationNumber); }
if (should_fast_fail(call, requestStartTime, httpSingleton))
{
if (call->traceCall) { HC_TRACE_INFORMATION(HTTPCLIENT, "HCHttpCallPerformExecute [ID %llu] Fast fail %d", TO_ULL(call->id), call->statusCode); }
XAsyncComplete(retryContext->outerAsyncBlock, S_OK, 0);
return;
}
auto nestedBlock = http_allocate_unique<XAsyncBlock>();
if (nestedBlock == nullptr)
{
XAsyncComplete(retryContext->outerAsyncBlock, E_OUTOFMEMORY, 0);
return;
}
XTaskQueueHandle nestedQueue = nullptr;
if (retryContext->outerQueue != nullptr)
{
XTaskQueuePortHandle workPort;
XTaskQueueGetPort(retryContext->outerQueue, XTaskQueuePort::Work, &workPort);
XTaskQueueCreateComposite(workPort, workPort, &nestedQueue);
}
nestedBlock->queue = nestedQueue;
nestedBlock->context = retryContext.get();
nestedBlock->callback = [](XAsyncBlock* nestedAsyncBlock)
{
HC_UNIQUE_PTR<XAsyncBlock> nestedAsyncPtr{ nestedAsyncBlock };
HC_UNIQUE_PTR<retry_context> retryContext{ static_cast<retry_context*>(nestedAsyncBlock->context) };
auto httpSingleton = get_http_singleton();
if (httpSingleton == nullptr)
{
HC_TRACE_WARNING(HTTPCLIENT, "Http completed after HCCleanup was called. Aborting call.");
XAsyncComplete(retryContext->outerAsyncBlock, E_HC_NOT_INITIALISED, 0);
}
else
{
auto callStatus = XAsyncGetStatus(nestedAsyncBlock, false);
auto responseReceivedTime = chrono_clock_t::now();
uint32_t timeoutWindowInSeconds = 0;
HC_CALL* call = retryContext->call->get();
HCHttpCallRequestGetTimeoutWindow(call, &timeoutWindowInSeconds);
notify_call_routed_handlers(httpSingleton, call);
if (SUCCEEDED(callStatus) && http_call_should_retry(call, responseReceivedTime))
{
if (call->traceCall) { HC_TRACE_INFORMATION(HTTPCLIENT, "HCHttpCallPerformExecute [ID %llu] Retry after %lld ms", TO_ULL(call->id), call->delayBeforeRetry.count()); }
clear_http_call_response(call);
retry_http_call_until_done(std::move(retryContext));
}
else
{
XAsyncComplete(retryContext->outerAsyncBlock, callStatus, 0);
}
}
if (nestedAsyncBlock->queue != nullptr)
{
XTaskQueueCloseHandle(nestedAsyncBlock->queue);
}
// Cleanup with happen when unique ptr's go out of scope
};
HRESULT hr = perform_http_call(httpSingleton, call, nestedBlock.get());
if (SUCCEEDED(hr))
{
nestedBlock.release(); // at this point we know do work will be called eventually
retryContext.release(); // at this point we know do work will be called eventually
}
else
{
// Cleanup with happen when unique ptr's go out of scope if they weren't released
XAsyncComplete(retryContext->outerAsyncBlock, hr, 0);
return;
}
}