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)); }
// 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)); }
/// <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)); }
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)); }
// 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); }
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); }
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); }
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) { }
public StartCommandOrchestrationArgs StringToStartCommandOrchestrationArgs(string input, OrchestrationClientAttribute attr) { return(!string.IsNullOrEmpty(input) ? JsonConvert.DeserializeObject <StartCommandOrchestrationArgs>(input) : null); }
// protected virtual to allow mocking in unit tests. protected virtual DurableOrchestrationClientBase GetClient(OrchestrationClientAttribute attribute) { return(this.config.GetClient(attribute)); }
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)); }