in src/WebJobs.Extensions.DurableTask/HttpApiHandler.cs [199:283]
internal async Task<HttpResponseMessage> WaitForCompletionOrCreateCheckStatusResponseAsync(
HttpRequestMessage request,
string instanceId,
DurableClientAttribute attribute,
TimeSpan timeout,
TimeSpan retryInterval,
bool returnInternalServerErrorOnFailure = false)
{
if (retryInterval > timeout)
{
throw new ArgumentException($"Total timeout {timeout.TotalSeconds} should be bigger than retry timeout {retryInterval.TotalSeconds}");
}
HttpManagementPayload httpManagementPayload = this.GetClientResponseLinks(request, instanceId, attribute?.TaskHub, attribute?.ConnectionName, returnInternalServerErrorOnFailure);
IDurableOrchestrationClient client = this.GetClient(request, attribute);
DurableOrchestrationStatus status = null;
if (client is DurableClient durableClient && durableClient.DurabilityProvider.SupportsPollFreeWait)
{
// For durability providers that support long polling, WaitForOrchestrationAsync is more efficient than GetStatusAsync
// so we ignore the retryInterval argument and instead wait for the entire timeout duration
var state = await durableClient.DurabilityProvider.WaitForOrchestrationAsync(instanceId, null, timeout, CancellationToken.None);
if (state != null)
{
status = DurableClient.ConvertOrchestrationStateToStatus(state);
}
}
else
{
// This retry loop completes either when the
// orchestration has completed, or when the timeout is reached.
Stopwatch stopwatch = Stopwatch.StartNew();
while (true)
{
status = await client.GetStatusAsync(instanceId);
if (status != null && (
status.RuntimeStatus == OrchestrationRuntimeStatus.Completed ||
status.RuntimeStatus == OrchestrationRuntimeStatus.Canceled ||
status.RuntimeStatus == OrchestrationRuntimeStatus.Failed ||
status.RuntimeStatus == OrchestrationRuntimeStatus.Terminated))
{
break;
}
TimeSpan elapsed = stopwatch.Elapsed;
if (elapsed < timeout)
{
TimeSpan remainingTime = timeout.Subtract(elapsed);
await Task.Delay(remainingTime > retryInterval ? retryInterval : remainingTime);
}
else
{
break;
}
}
}
switch (status?.RuntimeStatus)
{
case OrchestrationRuntimeStatus.Completed:
return request.CreateResponse(HttpStatusCode.OK, status.Output);
case OrchestrationRuntimeStatus.Canceled:
case OrchestrationRuntimeStatus.Failed:
case OrchestrationRuntimeStatus.Terminated:
return await this.HandleGetStatusRequestAsync(request, instanceId, returnInternalServerErrorOnFailure, client);
default:
return this.CreateCheckStatusResponseMessage(
request,
instanceId,
httpManagementPayload.StatusQueryGetUri,
httpManagementPayload.SendEventPostUri,
httpManagementPayload.TerminatePostUri,
httpManagementPayload.PurgeHistoryDeleteUri,
httpManagementPayload.RestartPostUri,
httpManagementPayload.SuspendPostUri,
httpManagementPayload.ResumePostUri);
}
}