internal async Task WaitForCompletionOrCreateCheckStatusResponseAsync()

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