Exemple #1
0
        private DurableOrchestrationClientBase GetClient(HttpRequestMessage request)
        {
            string taskHub        = null;
            string connectionName = null;

            var pairs = request.GetQueryNameValuePairs();

            foreach (var key in pairs.AllKeys)
            {
                if (taskHub == null &&
                    key.Equals(TaskHubParameter, StringComparison.OrdinalIgnoreCase) &&
                    !string.IsNullOrWhiteSpace(pairs[key]))
                {
                    taskHub = pairs[key];
                }
                else if (connectionName == null &&
                         key.Equals(ConnectionParameter, StringComparison.OrdinalIgnoreCase) &&
                         !string.IsNullOrWhiteSpace(pairs[key]))
                {
                    connectionName = pairs[key];
                }
            }

            var attribute = new OrchestrationClientAttribute
            {
                TaskHub        = taskHub,
                ConnectionName = connectionName,
            };

            return(this.GetClient(attribute));
        }
Exemple #2
0
 // Get a response that will point to our webhook handler.
 internal HttpResponseMessage CreateCheckStatusResponse(
     HttpRequestMessage request,
     string instanceId,
     OrchestrationClientAttribute attribute)
 {
     return(this.HttpApiHandler.CreateCheckStatusResponse(request, instanceId, attribute));
 }
        private void GetClientResponseLinks(
            HttpRequestMessage request,
            string instanceId,
            OrchestrationClientAttribute attribute,
            out string statusQueryGetUri,
            out string sendEventPostUri,
            out string terminatePostUri)
        {
            if (this.config.NotificationUrl == null)
            {
                throw new InvalidOperationException("Webhooks are not configured");
            }

            Uri notificationUri = this.config.NotificationUrl;

            // e.g. http://{host}/admin/extensions/DurableTaskExtension?code={systemKey}
            string hostUrl        = request.RequestUri.GetLeftPart(UriPartial.Authority);
            string baseUrl        = hostUrl + notificationUri.AbsolutePath.TrimEnd('/');
            string instancePrefix = baseUrl + InstancesControllerSegment + WebUtility.UrlEncode(instanceId);

            string taskHub    = WebUtility.UrlEncode(attribute.TaskHub ?? this.config.HubName);
            string connection = WebUtility.UrlEncode(attribute.ConnectionName ?? this.config.AzureStorageConnectionStringName ?? ConnectionStringNames.Storage);

            string querySuffix = $"{TaskHubParameter}={taskHub}&{ConnectionParameter}={connection}";

            if (!string.IsNullOrEmpty(notificationUri.Query))
            {
                // This is expected to include the auto-generated system key for this extension.
                querySuffix += "&" + notificationUri.Query.TrimStart('?');
            }

            statusQueryGetUri = instancePrefix + "?" + querySuffix;
            sendEventPostUri  = instancePrefix + "/" + RaiseEventOperation + "/{eventName}?" + querySuffix;
            terminatePostUri  = instancePrefix + "/" + TerminateOperation + "?reason={text}&" + querySuffix;
        }
 internal AzureStorageOrchestrationServiceSettings GetOrchestrationServiceSettings(
     OrchestrationClientAttribute attribute)
 {
     return(this.GetOrchestrationServiceSettings(
                connectionNameOverride: attribute.ConnectionName,
                taskHubNameOverride: attribute.TaskHub));
 }
Exemple #5
0
        /// <summary>
        /// Gets a <see cref="DurableOrchestrationClient"/> using configuration from a <see cref="OrchestrationClientAttribute"/> instance.
        /// </summary>
        /// <param name="attribute">The attribute containing the client configuration parameters.</param>
        /// <returns>Returns a <see cref="DurableOrchestrationClient"/> instance. The returned instance may be a cached instance.</returns>
        protected internal virtual DurableOrchestrationClient GetClient(OrchestrationClientAttribute attribute)
        {
            DurableOrchestrationClient client = this.cachedClients.GetOrAdd(
                attribute,
                attr =>
            {
                AzureStorageOrchestrationServiceSettings settings = this.GetOrchestrationServiceSettings(attr);

                AzureStorageOrchestrationService innerClient;
                if (this.orchestrationServiceSettings != null &&
                    this.orchestrationService != null &&
                    string.Equals(this.orchestrationServiceSettings.TaskHubName, settings.TaskHubName, StringComparison.OrdinalIgnoreCase) &&
                    string.Equals(this.orchestrationServiceSettings.StorageConnectionString, settings.StorageConnectionString, StringComparison.OrdinalIgnoreCase))
                {
                    // It's important that clients use the same AzureStorageOrchestrationService instance
                    // as the host when possible to ensure we any send operations can be picked up
                    // immediately instead of waiting for the next queue polling interval.
                    innerClient = this.orchestrationService;
                }
                else
                {
                    innerClient = new AzureStorageOrchestrationService(settings);
                }

                return(new DurableOrchestrationClient(innerClient, this, attr));
            });

            return(client);
        }
 internal HttpResponseMessage CreateCheckStatusResponse(
     HttpRequestMessage request,
     string instanceId,
     OrchestrationClientAttribute attribute)
 {
     this.GetClientResponseLinks(request, instanceId, attribute, out var statusQueryGetUri, out var sendEventPostUri, out var terminatePostUri);
     return(this.CreateCheckStatusResponseMessage(request, instanceId, statusQueryGetUri, sendEventPostUri, terminatePostUri));
 }
Exemple #7
0
        internal HttpResponseMessage CreateCheckStatusResponse(
            HttpRequestMessage request,
            string instanceId,
            OrchestrationClientAttribute attribute)
        {
            HttpManagementPayload httpManagementPayload = this.GetClientResponseLinks(request, instanceId, attribute?.TaskHub, attribute?.ConnectionName);

            return(this.CreateCheckStatusResponseMessage(request, httpManagementPayload.Id, httpManagementPayload.StatusQueryGetUri, httpManagementPayload.SendEventPostUri, httpManagementPayload.TerminatePostUri, httpManagementPayload.RewindPostUri));
        }
        internal async Task <HttpResponseMessage> WaitForCompletionOrCreateCheckStatusResponseAsync(
            HttpRequestMessage request,
            string instanceId,
            OrchestrationClientAttribute attribute,
            TimeSpan timeout,
            TimeSpan retryInterval)
        {
            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);

            DurableOrchestrationClientBase client = this.GetClient(request);
            Stopwatch stopwatch = Stopwatch.StartNew();

            while (true)
            {
                DurableOrchestrationStatus status = await client.GetStatusAsync(instanceId);

                if (status != null)
                {
                    if (status.RuntimeStatus == OrchestrationRuntimeStatus.Completed)
                    {
                        return(request.CreateResponse(HttpStatusCode.OK, status.Output));
                    }

                    if (status.RuntimeStatus == OrchestrationRuntimeStatus.Canceled ||
                        status.RuntimeStatus == OrchestrationRuntimeStatus.Failed ||
                        status.RuntimeStatus == OrchestrationRuntimeStatus.Terminated)
                    {
                        return(await this.HandleGetStatusRequestAsync(request, instanceId));
                    }
                }

                TimeSpan elapsed = stopwatch.Elapsed;
                if (elapsed < timeout)
                {
                    TimeSpan remainingTime = timeout.Subtract(elapsed);
                    await Task.Delay(remainingTime > retryInterval?retryInterval : remainingTime);
                }
                else
                {
                    return(this.CreateCheckStatusResponseMessage(
                               request,
                               instanceId,
                               httpManagementPayload.StatusQueryGetUri,
                               httpManagementPayload.SendEventPostUri,
                               httpManagementPayload.TerminatePostUri,
                               httpManagementPayload.RewindPostUri,
                               httpManagementPayload.PurgeHistoryDeleteUri));
                }
            }
        }
        // Get a response that will point to our webhook handler.
        internal HttpResponseMessage CreateCheckStatusResponse(
            HttpRequestMessage request,
            string instanceId,
            OrchestrationClientAttribute attribute)
        {
            if (this.DisableHttpManagementApis)
            {
                throw new InvalidOperationException("HTTP instance management APIs are disabled.");
            }

            return(this.httpApiHandler.CreateCheckStatusResponse(request, instanceId, attribute));
        }
        /// <summary>
        /// Gets a <see cref="DurableOrchestrationClient"/> using configuration from a <see cref="OrchestrationClientAttribute"/> instance.
        /// </summary>
        /// <param name="attribute">The attribute containing the client configuration parameters.</param>
        /// <returns>Returns a <see cref="DurableOrchestrationClient"/> instance. The returned instance may be a cached instance.</returns>
        protected internal virtual DurableOrchestrationClient GetClient(OrchestrationClientAttribute attribute)
        {
            DurableOrchestrationClient client = this.cachedClients.GetOrAdd(
                attribute,
                attr =>
            {
                AzureStorageOrchestrationServiceSettings settings = this.GetOrchestrationServiceSettings(attr);
                var innerClient = new AzureStorageOrchestrationService(settings);
                return(new DurableOrchestrationClient(innerClient, this, attr, this.traceHelper));
            });

            return(client);
        }
        // Get a response that will wait for response from the durable function for predefined period of time before
        // pointing to our webhook handler.
        internal async Task <HttpResponseMessage> WaitForCompletionOrCreateCheckStatusResponseAsync(
            HttpRequestMessage request,
            string instanceId,
            OrchestrationClientAttribute attribute,
            TimeSpan timeout,
            TimeSpan retryInterval)
        {
            if (this.DisableHttpManagementApis)
            {
                throw new InvalidOperationException("HTTP instance management APIs are disabled.");
            }

            return(await this.httpApiHandler.WaitForCompletionOrCreateCheckStatusResponseAsync(request, instanceId, attribute, timeout, retryInterval));
        }
Exemple #12
0
 // Get a response that will wait for response from the durable function for predefined period of time before
 // pointing to our webhook handler.
 internal async Task <HttpResponseMessage> WaitForCompletionOrCreateCheckStatusResponseAsync(
     HttpRequestMessage request,
     string instanceId,
     OrchestrationClientAttribute attribute,
     TimeSpan timeout,
     TimeSpan retryInterval)
 {
     return(await this.HttpApiHandler.WaitForCompletionOrCreateCheckStatusResponseAsync(
                request,
                instanceId,
                attribute,
                timeout,
                retryInterval));
 }
        internal HttpResponseMessage CreateCheckStatusResponse(
            HttpRequestMessage request,
            string instanceId,
            OrchestrationClientAttribute attribute)
        {
            if (this.config.NotificationUrl == null)
            {
                throw new InvalidOperationException("Webhooks are not configured");
            }

            Uri notificationUri = this.config.NotificationUrl;

            // e.g. http://{host}/admin/extensions/DurableTaskExtension?code={systemKey}
            string hostUrl        = request.RequestUri.GetLeftPart(UriPartial.Authority);
            string baseUrl        = hostUrl + notificationUri.AbsolutePath.TrimEnd('/');
            string instancePrefix = baseUrl + InstancesControllerSegment + WebUtility.UrlEncode(instanceId);

            string taskHub    = WebUtility.UrlEncode(attribute.TaskHub ?? config.HubName);
            string connection = WebUtility.UrlEncode(attribute.ConnectionName ?? config.AzureStorageConnectionStringName ?? ConnectionStringNames.Storage);

            string querySuffix = $"{TaskHubParameter}={taskHub}&{ConnectionParameter}={connection}";

            if (!string.IsNullOrEmpty(notificationUri.Query))
            {
                // This is expected to include the auto-generated system key for this extension.
                querySuffix += "&" + notificationUri.Query.TrimStart('?');
            }

            string statusQueryGetUri = instancePrefix + "?" + querySuffix;
            string sendEventPostUri  = instancePrefix + "/" + RaiseEventOperation + "/{eventName}?" + querySuffix;
            string terminatePostUri  = instancePrefix + "/" + TerminateOperation + "?reason={text}&" + querySuffix;

            HttpResponseMessage response = request.CreateResponse(
                HttpStatusCode.Accepted,
                new
            {
                id = instanceId,
                statusQueryGetUri = statusQueryGetUri,
                sendEventPostUri  = sendEventPostUri,
                terminatePostUri  = terminatePostUri
            });

            // Implement the async HTTP 202 pattern.
            response.Headers.Location   = new Uri(statusQueryGetUri);
            response.Headers.RetryAfter = new RetryConditionHeaderValue(TimeSpan.FromSeconds(10));
            return(response);
        }
Exemple #14
0
        public void Configure(IWebJobsBuilder builder)
        {
            builder.AddExtension <ActorExtension>();


            builder.Services.AddSingleton <IDurableOrchestrationClient>(sp =>
            {
                var configurations = sp.GetServices <IExtensionConfigProvider>();

                var durableTaskExtension = configurations.OfType <DurableTaskExtension>().FirstOrDefault();

                var getclient = durableTaskExtension.GetType().GetMethod("GetClient", BindingFlags.NonPublic | BindingFlags.Instance);
                var orchestrationClientAttribute = new OrchestrationClientAttribute();



                var client = getclient.Invoke(durableTaskExtension, new object[] { orchestrationClientAttribute });

                return(client as IDurableOrchestrationClient);
            });
        }
        internal HttpResponseMessage CreateCheckStatusResponse(
            HttpRequestMessage request,
            string instanceId,
            OrchestrationClientAttribute attribute)
        {
            if (this.config.NotificationUrl == null)
            {
                throw new InvalidOperationException("Webhooks are not configured");
            }

            // e.g. http://{host}/admin/extensions/DurableTaskConfiguration
            string hostUrl        = request.RequestUri.GetLeftPart(UriPartial.Authority);
            string baseUrl        = hostUrl + this.config.NotificationUrl.AbsolutePath.TrimEnd('/');
            string instancePrefix = baseUrl + InstancesControllerSegment + WebUtility.UrlEncode(instanceId);

            string taskHub     = WebUtility.UrlEncode(attribute.TaskHub ?? config.HubName);
            string connection  = WebUtility.UrlEncode(attribute.ConnectionName ?? config.AzureStorageConnectionStringName ?? ConnectionStringNames.Storage);
            string querySuffix = $"{TaskHubParameter}={taskHub}&{ConnectionParameter}={connection}";

            Uri statusQueryGetUri = new Uri(instancePrefix + "?" + querySuffix);
            Uri sendEventPostUri  = new Uri(instancePrefix + "/" + RaiseEventOperation + "/{eventName}?" + querySuffix);
            Uri terminatePostUri  = new Uri(instancePrefix + "/" + TerminateOperation + "?reason={text}&" + querySuffix);

            HttpResponseMessage response = request.CreateResponse(
                HttpStatusCode.Accepted,
                new
            {
                id = instanceId,
                statusQueryGetUri = statusQueryGetUri,
                sendEventPostUri  = sendEventPostUri,
                terminatePostUri  = terminatePostUri
            });

            response.Headers.Location = statusQueryGetUri;
            return(response);
        }
Exemple #16
0
            protected internal override DurableOrchestrationClient GetClient(OrchestrationClientAttribute attribute)
            {
                var orchestrationServiceClientMock = new Mock <IOrchestrationServiceClient>();

                return(new DurableOrchestrationClientMock(orchestrationServiceClientMock.Object, this, attribute));
            }
 protected override DurableOrchestrationClientBase GetClient(OrchestrationClientAttribute attribute)
 {
     return(this.innerClient);
 }
Exemple #18
0
 internal DurableOrchestrationClientMock(IOrchestrationServiceClient serviceClient, DurableTaskExtension config, OrchestrationClientAttribute attribute)
     : base(serviceClient, config, attribute)
 {
 }
 public StartOrchestrationArgs JObjectToStartOrchestrationArgs(JObject input, OrchestrationClientAttribute attr)
 {
     return(input?.ToObject <StartOrchestrationArgs>());
 }
        public IAsyncCollector <StartOrchestrationArgs> CreateAsyncCollector(OrchestrationClientAttribute clientAttribute)
        {
            DurableOrchestrationClientBase client = this.config.GetClient(clientAttribute);

            return(new OrchestrationClientAsyncCollector(client));
        }
 internal DurableOrchestrationClientMock(IOrchestrationServiceClient serviceClient, DurableTaskExtension config, OrchestrationClientAttribute attribute, EndToEndTraceHelper traceHelper)
     : base(serviceClient, config, attribute, traceHelper)
 {
 }
Exemple #22
0
 public StartCommandOrchestrationArgs StringToStartCommandOrchestrationArgs(string input,
                                                                            OrchestrationClientAttribute attr)
 {
     return(!string.IsNullOrEmpty(input) ? JsonConvert.DeserializeObject <StartCommandOrchestrationArgs>(input) : null);
 }
Exemple #23
0
 // protected virtual to allow mocking in unit tests.
 protected virtual DurableOrchestrationClientBase GetClient(OrchestrationClientAttribute attribute)
 {
     return(this.config.GetClient(attribute));
 }
Exemple #24
0
        public string DurableOrchestrationClientToString(DurableOrchestrationClient client, OrchestrationClientAttribute attr)
        {
            var payload = new OrchestrationClientInputData
            {
                TaskHubName    = client.TaskHubName,
                CreationUrls   = this.config.HttpApiHandler.GetInstanceCreationLinks(),
                ManagementUrls = this.config.HttpApiHandler.CreateHttpManagementPayload(InstanceIdPlaceholder, attr?.TaskHub, attr?.ConnectionName),
            };

            return(JsonConvert.SerializeObject(payload));
        }