From f95755b5bdba8e3a0837da013ca9dcbeb7b611c9 Mon Sep 17 00:00:00 2001 From: David Revoledo Date: Tue, 27 Oct 2020 19:33:06 -0300 Subject: [PATCH] Add IDurableClientFactory abstraction (#1125) Use a new dependency injection abstraction to make the creation of `IDurableClient` objects simpler. This has two large benefits: 1. It allows `IDurableClient` instances to be utilized via services that are injected via Dependency Injection. 2. It allows apps that aren't explicitly Durable Functions apps to create instances of `IDurableClient` to manage their Durable Entities and Orchestrations. Co-authored-by: davidrevoledo1@gmail.com --- .../ContextImplementations/DurableClient.cs | 32 +++-- .../DurableClientFactory.cs | 115 +++++++++++++++ .../IDurableClientFactory.cs | 26 ++++ .../DurableClientAttribute.cs | 22 +++ .../DurableTaskExtension.cs | 6 +- ...rableTaskJobHostConfigurationExtensions.cs | 37 +++++ .../HttpApiHandler.cs | 58 ++++---- .../LocalHttpListener.cs | 14 +- ....WebJobs.Extensions.DurableTask-net461.xml | 117 ++++++++++++++++ ...t.Azure.WebJobs.Extensions.DurableTask.xml | 132 ++++++++++++++++++ .../Options/DurableClientOptions.cs | 40 ++++++ .../Options/DurableTaskOptions.cs | 3 +- .../StandardConnectionStringProvider.cs | 34 +++++ 13 files changed, 591 insertions(+), 45 deletions(-) create mode 100644 src/WebJobs.Extensions.DurableTask/ContextImplementations/DurableClientFactory.cs create mode 100644 src/WebJobs.Extensions.DurableTask/ContextImplementations/IDurableClientFactory.cs create mode 100644 src/WebJobs.Extensions.DurableTask/Options/DurableClientOptions.cs create mode 100644 src/WebJobs.Extensions.DurableTask/StandardConnectionStringProvider.cs diff --git a/src/WebJobs.Extensions.DurableTask/ContextImplementations/DurableClient.cs b/src/WebJobs.Extensions.DurableTask/ContextImplementations/DurableClient.cs index 4c73ec38f..bd9f47498 100644 --- a/src/WebJobs.Extensions.DurableTask/ContextImplementations/DurableClient.cs +++ b/src/WebJobs.Extensions.DurableTask/ContextImplementations/DurableClient.cs @@ -41,25 +41,37 @@ private static readonly OrchestrationRuntimeStatus[] RunningStatus private readonly DurableTaskExtension config; private readonly DurableClientAttribute attribute; // for rehydrating a Client after a webhook private readonly MessagePayloadDataConverter messageDataConverter; + private readonly DurableTaskOptions durableTaskOptions; internal DurableClient( DurabilityProvider serviceClient, - DurableTaskExtension config, HttpApiHandler httpHandler, - DurableClientAttribute attribute) + DurableClientAttribute attribute, + MessagePayloadDataConverter messageDataConverter, + EndToEndTraceHelper traceHelper, + DurableTaskOptions durableTaskOptions) { - this.config = config ?? throw new ArgumentNullException(nameof(config)); - - this.messageDataConverter = config.MessageDataConverter; + this.messageDataConverter = messageDataConverter; this.client = new TaskHubClient(serviceClient, this.messageDataConverter); this.durabilityProvider = serviceClient; - this.traceHelper = config.TraceHelper; + this.traceHelper = traceHelper; this.httpApiHandler = httpHandler; - this.hubName = attribute.TaskHub ?? config.Options.HubName; + this.durableTaskOptions = durableTaskOptions; + this.hubName = attribute.TaskHub ?? this.durableTaskOptions.HubName; this.attribute = attribute; } + internal DurableClient( + DurabilityProvider serviceClient, + DurableTaskExtension config, + HttpApiHandler httpHandler, + DurableClientAttribute attribute) + : this(serviceClient, httpHandler, attribute, config.MessageDataConverter, config.TraceHelper, config.Options) + { + this.config = config; + } + public string TaskHubName => this.hubName; internal DurabilityProvider DurabilityProvider => this.durabilityProvider; @@ -113,7 +125,7 @@ async Task IDurableOrchestrationClient.WaitForCompletionOrCreateC /// async Task IDurableOrchestrationClient.StartNewAsync(string orchestratorFunctionName, string instanceId, T input) { - if (this.ClientReferencesCurrentApp(this)) + if (!this.attribute.ExternalClient && this.ClientReferencesCurrentApp(this)) { this.config.ThrowIfFunctionDoesNotExist(orchestratorFunctionName, FunctionType.Orchestrator); } @@ -154,7 +166,7 @@ async Task IDurableOrchestrationClient.StartNewAsync(string orchestra private OrchestrationStatus[] GetStatusesNotToOverride() { - var overridableStates = this.config.Options.OverridableExistingInstanceStates; + var overridableStates = this.durableTaskOptions.OverridableExistingInstanceStates; if (overridableStates == OverridableStates.NonRunningStates) { return new OrchestrationStatus[] @@ -322,7 +334,7 @@ private bool ClientReferencesCurrentApp(DurableClient client) private bool TaskHubMatchesCurrentApp(DurableClient client) { - var taskHubName = this.config.Options.HubName; + var taskHubName = this.durableTaskOptions.HubName; return client.TaskHubName.Equals(taskHubName); } diff --git a/src/WebJobs.Extensions.DurableTask/ContextImplementations/DurableClientFactory.cs b/src/WebJobs.Extensions.DurableTask/ContextImplementations/DurableClientFactory.cs new file mode 100644 index 000000000..cc22f68dd --- /dev/null +++ b/src/WebJobs.Extensions.DurableTask/ContextImplementations/DurableClientFactory.cs @@ -0,0 +1,115 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Concurrent; +using Microsoft.Azure.WebJobs.Extensions.DurableTask.Options; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; + +namespace Microsoft.Azure.WebJobs.Extensions.DurableTask.ContextImplementations +{ + /// + /// Factory class to create Durable Client to start works outside an azure function context. + /// + public class DurableClientFactory : IDurableClientFactory, IDisposable + { + // Creating client objects is expensive, so we cache them when the attributes match. + // Note that DurableClientAttribute defines a custom equality comparer. + private readonly ConcurrentDictionary cachedClients = + new ConcurrentDictionary(); + + private readonly ConcurrentDictionary cachedHttpListeners = + new ConcurrentDictionary(); + + private readonly DurableClientOptions defaultDurableClientOptions; + private readonly DurableTaskOptions durableTaskOptions; + private readonly IDurabilityProviderFactory durabilityProviderFactory; + private readonly ILogger logger; + + /// + /// Initializes a new instance of the class. + /// + /// Default Options to Build Durable Clients. + /// The factory used to create orchestration service based on the configured storage provider. + /// The logger factory used for extension-specific logging and orchestration tracking. + /// The configuration options for this extension. + /// The factory used to create for message settings. + public DurableClientFactory( + IOptions defaultDurableClientOptions, + IOptions durableTaskOptions, + IDurabilityProviderFactory orchestrationServiceFactory, + ILoggerFactory loggerFactory, + IMessageSerializerSettingsFactory messageSerializerSettingsFactory = null) + { + this.logger = loggerFactory.CreateLogger(DurableTaskExtension.LoggerCategoryName); + + this.durabilityProviderFactory = orchestrationServiceFactory; + this.defaultDurableClientOptions = defaultDurableClientOptions.Value; + this.durableTaskOptions = durableTaskOptions?.Value ?? new DurableTaskOptions(); + + this.MessageDataConverter = DurableTaskExtension.CreateMessageDataConverter(messageSerializerSettingsFactory); + this.TraceHelper = new EndToEndTraceHelper(this.logger, this.durableTaskOptions.Tracing.TraceReplayEvents); + } + + internal MessagePayloadDataConverter MessageDataConverter { get; private set; } + + internal EndToEndTraceHelper TraceHelper { get; private set; } + + /// + /// Gets a using configuration from a instance. + /// + /// options containing the client configuration parameters. + /// Returns a instance. The returned instance may be a cached instance. + public IDurableClient CreateClient(DurableClientOptions durableClientOptions) + { + if (durableClientOptions == null) + { + throw new ArgumentException("Please configure 'DurableClientOptions'"); + } + + if (string.IsNullOrWhiteSpace(durableClientOptions.TaskHub)) + { + throw new ArgumentException("Please provide value for 'TaskHub'"); + } + + DurableClientAttribute attribute = new DurableClientAttribute(durableClientOptions); + + HttpApiHandler httpApiHandler = this.cachedHttpListeners.GetOrAdd( + attribute, + attr => + { + return new HttpApiHandler(null, null, this.durableTaskOptions, this.logger); + }); + + DurableClient client = this.cachedClients.GetOrAdd( + attribute, + attr => + { + DurabilityProvider innerClient = this.durabilityProviderFactory.GetDurabilityProvider(attribute); + return new DurableClient(innerClient, httpApiHandler, attribute, this.MessageDataConverter, this.TraceHelper, this.durableTaskOptions); + }); + + return client; + } + + /// + /// Gets a using configuration from a instance. + /// + /// Returns a instance. The returned instance may be a cached instance. + public IDurableClient CreateClient() + { + return this.CreateClient(this.defaultDurableClientOptions); + } + + /// + public void Dispose() + { + foreach (var cachedHttpListener in this.cachedHttpListeners) + { + cachedHttpListener.Value?.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/src/WebJobs.Extensions.DurableTask/ContextImplementations/IDurableClientFactory.cs b/src/WebJobs.Extensions.DurableTask/ContextImplementations/IDurableClientFactory.cs new file mode 100644 index 000000000..fbf4b5e49 --- /dev/null +++ b/src/WebJobs.Extensions.DurableTask/ContextImplementations/IDurableClientFactory.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.Azure.WebJobs.Extensions.DurableTask.Options; + +namespace Microsoft.Azure.WebJobs.Extensions.DurableTask.ContextImplementations +{ + /// + /// Factory class to create Durable Client to start works outside an azure function context. + /// + public interface IDurableClientFactory + { + /// + /// Gets a using configuration from a instance. + /// + /// options containing the client configuration parameters. + /// Returns a instance. The returned instance may be a cached instance. + IDurableClient CreateClient(DurableClientOptions durableClientOptions); + + /// + /// Gets a using configuration from a instance. + /// + /// Returns a instance. The returned instance may be a cached instance. + IDurableClient CreateClient(); + } +} \ No newline at end of file diff --git a/src/WebJobs.Extensions.DurableTask/DurableClientAttribute.cs b/src/WebJobs.Extensions.DurableTask/DurableClientAttribute.cs index faddbefb1..10984dafe 100644 --- a/src/WebJobs.Extensions.DurableTask/DurableClientAttribute.cs +++ b/src/WebJobs.Extensions.DurableTask/DurableClientAttribute.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using Microsoft.Azure.WebJobs.Description; +using Microsoft.Azure.WebJobs.Extensions.DurableTask.Options; namespace Microsoft.Azure.WebJobs.Extensions.DurableTask { @@ -15,6 +16,22 @@ namespace Microsoft.Azure.WebJobs.Extensions.DurableTask [Binding] public class DurableClientAttribute : Attribute, IEquatable { + /// + /// Initializes a new instance of the class. + /// + public DurableClientAttribute() { } + + /// + /// Initializes a new instance of the class. + /// + /// durable client options + public DurableClientAttribute(DurableClientOptions durableClientOptions) + { + this.TaskHub = durableClientOptions.TaskHub; + this.ConnectionName = durableClientOptions.ConnectionName; + this.ExternalClient = durableClientOptions.IsExternalClient; + } + /// /// Optional. Gets or sets the name of the task hub in which the orchestration data lives. /// @@ -39,6 +56,11 @@ public class DurableClientAttribute : Attribute, IEquatable public string ConnectionName { get; set; } + /// + /// Indicate if the client is External from the azure function where orchestrator functions are hosted. + /// + public bool ExternalClient { get; set; } + /// /// Returns a hash code for this attribute. /// diff --git a/src/WebJobs.Extensions.DurableTask/DurableTaskExtension.cs b/src/WebJobs.Extensions.DurableTask/DurableTaskExtension.cs index 56bb497b6..c8845d312 100644 --- a/src/WebJobs.Extensions.DurableTask/DurableTaskExtension.cs +++ b/src/WebJobs.Extensions.DurableTask/DurableTaskExtension.cs @@ -43,7 +43,7 @@ public class DurableTaskExtension : INameVersionObjectManager, INameVersionObjectManager { - private static readonly string LoggerCategoryName = LogCategories.CreateTriggerCategory("DurableTask"); + internal static readonly string LoggerCategoryName = LogCategories.CreateTriggerCategory("DurableTask"); // Creating client objects is expensive, so we cache them when the attributes match. // Note that DurableClientAttribute defines a custom equality comparer. @@ -133,7 +133,7 @@ public DurableTaskExtension( DurableHttpClientFactory durableHttpClientFactory = new DurableHttpClientFactory(); this.durableHttpClient = durableHttpClientFactory.GetClient(durableHttpMessageHandlerFactory); - this.MessageDataConverter = this.CreateMessageDataConverter(messageSerializerSettingsFactory); + this.MessageDataConverter = CreateMessageDataConverter(messageSerializerSettingsFactory); this.ErrorDataConverter = this.CreateErrorDataConverter(errorSerializerSettingsFactory); this.HttpApiHandler = new HttpApiHandler(this, logger); @@ -189,7 +189,7 @@ public string HubName internal MessagePayloadDataConverter ErrorDataConverter { get; private set; } - private MessagePayloadDataConverter CreateMessageDataConverter(IMessageSerializerSettingsFactory messageSerializerSettingsFactory) + internal static MessagePayloadDataConverter CreateMessageDataConverter(IMessageSerializerSettingsFactory messageSerializerSettingsFactory) { bool isDefault; if (messageSerializerSettingsFactory == null) diff --git a/src/WebJobs.Extensions.DurableTask/DurableTaskJobHostConfigurationExtensions.cs b/src/WebJobs.Extensions.DurableTask/DurableTaskJobHostConfigurationExtensions.cs index 2f9113bfd..2afdcc8fb 100644 --- a/src/WebJobs.Extensions.DurableTask/DurableTaskJobHostConfigurationExtensions.cs +++ b/src/WebJobs.Extensions.DurableTask/DurableTaskJobHostConfigurationExtensions.cs @@ -5,6 +5,8 @@ using System.Net.Http; using System.Threading; #if !FUNCTIONS_V1 +using Microsoft.Azure.WebJobs.Extensions.DurableTask.ContextImplementations; +using Microsoft.Azure.WebJobs.Extensions.DurableTask.Options; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; @@ -43,10 +45,45 @@ public static IWebJobsBuilder AddDurableTask(this IWebJobsBuilder builder) serviceCollection.TryAddSingleton(); serviceCollection.TryAddSingleton(); serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); return builder; } + /// + /// Adds the Durable Task extension to the provided . + /// + /// The to configure. + /// Returns the provided . + public static IServiceCollection AddDurableTask(this IServiceCollection serviceCollection) + { + if (serviceCollection == null) + { + throw new ArgumentNullException(nameof(serviceCollection)); + } + + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + + return serviceCollection; + } + + /// + /// Adds the Durable Task extension to the provided . + /// + /// The to configure. + /// Populate default configurations of to create Durable Clients. + /// Returns the provided . + public static IServiceCollection AddDurableTask(this IServiceCollection serviceCollection, Action optionsBuilder) + { + AddDurableTask(serviceCollection); + serviceCollection.Configure(optionsBuilder.Invoke); + return serviceCollection; + } + /// /// Adds the Durable Task extension to the provided . /// diff --git a/src/WebJobs.Extensions.DurableTask/HttpApiHandler.cs b/src/WebJobs.Extensions.DurableTask/HttpApiHandler.cs index 5c3894eea..891b46f6e 100644 --- a/src/WebJobs.Extensions.DurableTask/HttpApiHandler.cs +++ b/src/WebJobs.Extensions.DurableTask/HttpApiHandler.cs @@ -61,23 +61,37 @@ internal class HttpApiHandler : IDisposable private static readonly TemplateMatcher InstancesRoute = GetInstancesRoute(); private static readonly TemplateMatcher InstanceRaiseEventRoute = GetInstanceRaiseEventRoute(); - private readonly DurableTaskExtension config; private readonly ILogger logger; private readonly MessagePayloadDataConverter messageDataConverter; private readonly LocalHttpListener localHttpListener; + private readonly EndToEndTraceHelper traceHelper; + private readonly DurableTaskOptions durableTaskOptions; + private readonly DurableTaskExtension config; - public HttpApiHandler(DurableTaskExtension config, ILogger logger) + public HttpApiHandler( + EndToEndTraceHelper traceHelper, + MessagePayloadDataConverter messageDataConverter, + DurableTaskOptions durableTaskOptions, + ILogger logger) { - this.config = config; - this.messageDataConverter = this.config.MessageDataConverter; + this.messageDataConverter = messageDataConverter; this.logger = logger; + this.durableTaskOptions = durableTaskOptions; + this.traceHelper = traceHelper; // The listen URL must not include the path. this.localHttpListener = new LocalHttpListener( - config, + this.traceHelper, + this.durableTaskOptions, this.HandleRequestAsync); } + public HttpApiHandler(DurableTaskExtension config, ILogger logger) + : this(config.TraceHelper, config.MessageDataConverter, config.Options, logger) + { + this.config = config; + } + public void Dispose() { this.localHttpListener.Dispose(); @@ -215,9 +229,9 @@ public async Task HandleRequestAsync(HttpRequestMessage req { basePath = this.localHttpListener.InternalRpcUri.AbsolutePath; } - else if (this.config.Options.NotificationUrl != null) + else if (this.durableTaskOptions.NotificationUrl != null) { - basePath = this.config.Options.NotificationUrl.AbsolutePath; + basePath = this.durableTaskOptions.NotificationUrl.AbsolutePath; } else { @@ -550,15 +564,7 @@ private async Task HandleGetStatusRequestAsync( // The orchestration has failed - return 500 w/out Location header case OrchestrationRuntimeStatus.Failed: - if (returnInternalServerErrorOnFailure) - { - statusCode = HttpStatusCode.InternalServerError; - } - else - { - statusCode = HttpStatusCode.OK; - } - + statusCode = returnInternalServerErrorOnFailure ? HttpStatusCode.InternalServerError : HttpStatusCode.OK; location = null; break; @@ -901,7 +907,7 @@ internal string GetBaseUrl() { this.ThrowIfWebhooksNotConfigured(); - Uri notificationUri = this.config.Options.NotificationUrl; + Uri notificationUri = this.durableTaskOptions.NotificationUrl; string hostUrl = notificationUri.GetLeftPart(UriPartial.Authority); return hostUrl + notificationUri.AbsolutePath.TrimEnd('/'); @@ -911,7 +917,7 @@ internal string GetUniversalQueryStrings() { this.ThrowIfWebhooksNotConfigured(); - Uri notificationUri = this.config.Options.NotificationUrl; + Uri notificationUri = this.durableTaskOptions.NotificationUrl; return !string.IsNullOrEmpty(notificationUri.Query) ? notificationUri.Query.TrimStart('?') @@ -943,7 +949,7 @@ private HttpManagementPayload GetClientResponseLinks( { this.ThrowIfWebhooksNotConfigured(); - Uri notificationUri = this.config.Options.NotificationUrl; + Uri notificationUri = this.durableTaskOptions.NotificationUrl; Uri baseUri = request?.RequestUri ?? notificationUri; // e.g. http://{host}/runtime/webhooks/durabletask?code={systemKey} @@ -952,7 +958,7 @@ private HttpManagementPayload GetClientResponseLinks( string allInstancesPrefix = baseUrl + "/" + InstancesControllerSegment; string instancePrefix = allInstancesPrefix + WebUtility.UrlEncode(instanceId); - string taskHub = WebUtility.UrlEncode(taskHubName ?? this.config.Options.HubName); + string taskHub = WebUtility.UrlEncode(taskHubName ?? this.durableTaskOptions.HubName); string connection = WebUtility.UrlEncode(connectionName ?? this.config.GetDefaultConnectionName()); string querySuffix = $"{TaskHubParameter}={taskHub}&{ConnectionParameter}={connection}"; @@ -1007,7 +1013,7 @@ private HttpResponseMessage CreateCheckStatusResponseMessage( private void ThrowIfWebhooksNotConfigured() { - if (this.config.Options.NotificationUrl == null) + if (this.durableTaskOptions.NotificationUrl == null) { throw new InvalidOperationException("Webhooks are not configured"); } @@ -1015,7 +1021,7 @@ private void ThrowIfWebhooksNotConfigured() internal bool TryGetRpcBaseUrl(out Uri rpcBaseUrl) { - if (this.config.Options.LocalRpcEndpointEnabled != false) + if (this.durableTaskOptions.LocalRpcEndpointEnabled != false) { rpcBaseUrl = this.localHttpListener.InternalRpcUri; return true; @@ -1031,8 +1037,8 @@ internal async Task StartLocalHttpServerAsync() { if (!this.localHttpListener.IsListening) { - this.config.TraceHelper.ExtensionInformationalEvent( - this.config.Options.HubName, + this.traceHelper.ExtensionInformationalEvent( + this.durableTaskOptions.HubName, instanceId: string.Empty, functionName: string.Empty, message: $"Opening local RPC endpoint: {this.localHttpListener.InternalRpcUri}", @@ -1046,8 +1052,8 @@ internal async Task StopLocalHttpServerAsync() { if (this.localHttpListener.IsListening) { - this.config.TraceHelper.ExtensionInformationalEvent( - this.config.Options.HubName, + this.traceHelper.ExtensionInformationalEvent( + this.durableTaskOptions.HubName, instanceId: string.Empty, functionName: string.Empty, message: $"Closing local RPC endpoint: {this.localHttpListener.InternalRpcUri}", diff --git a/src/WebJobs.Extensions.DurableTask/LocalHttpListener.cs b/src/WebJobs.Extensions.DurableTask/LocalHttpListener.cs index 9aafdbe8e..9d31281f1 100644 --- a/src/WebJobs.Extensions.DurableTask/LocalHttpListener.cs +++ b/src/WebJobs.Extensions.DurableTask/LocalHttpListener.cs @@ -22,16 +22,20 @@ internal class LocalHttpListener : IDisposable { private const int DefaultPort = 17071; - private readonly DurableTaskExtension extension; private readonly IWebHost localWebHost; private readonly Func> handler; + private readonly EndToEndTraceHelper traceHelper; + private readonly DurableTaskOptions durableTaskOptions; public LocalHttpListener( - DurableTaskExtension extension, + EndToEndTraceHelper traceHelper, + DurableTaskOptions durableTaskOptions, Func> handler) { - this.extension = extension ?? throw new ArgumentNullException(nameof(extension)); + this.traceHelper = traceHelper ?? throw new ArgumentNullException(nameof(traceHelper)); this.handler = handler ?? throw new ArgumentNullException(nameof(handler)); + this.durableTaskOptions = durableTaskOptions ?? throw new ArgumentNullException(nameof(durableTaskOptions)); + #if !FUNCTIONS_V1 this.InternalRpcUri = new Uri($"http://127.0.0.1:{this.GetAvailablePort()}/durabletask/"); var listenUri = new Uri(this.InternalRpcUri.GetLeftPart(UriPartial.Authority)); @@ -114,8 +118,8 @@ private async Task HandleRequestAsync(HttpContext context) } catch (Exception e) { - this.extension.TraceHelper.ExtensionWarningEvent( - this.extension.Options.HubName, + this.traceHelper.ExtensionWarningEvent( + this.durableTaskOptions.HubName, functionName: string.Empty, instanceId: string.Empty, message: $"Unhandled exception in HTTP API handler: {e}"); diff --git a/src/WebJobs.Extensions.DurableTask/Microsoft.Azure.WebJobs.Extensions.DurableTask-net461.xml b/src/WebJobs.Extensions.DurableTask/Microsoft.Azure.WebJobs.Extensions.DurableTask-net461.xml index 819a789ae..0bcb5d515 100644 --- a/src/WebJobs.Extensions.DurableTask/Microsoft.Azure.WebJobs.Extensions.DurableTask-net461.xml +++ b/src/WebJobs.Extensions.DurableTask/Microsoft.Azure.WebJobs.Extensions.DurableTask-net461.xml @@ -174,6 +174,55 @@ + + + Factory class to create Durable Client to start works outside an azure function context. + + + + + Initializes a new instance of the class. + + Default Options to Build Durable Clients. + The factory used to create orchestration service based on the configured storage provider. + The logger factory used for extension-specific logging and orchestration tracking. + The configuration options for this extension. + The factory used to create for message settings. + + + + Gets a using configuration from a instance. + + options containing the client configuration parameters. + Returns a instance. The returned instance may be a cached instance. + + + + Gets a using configuration from a instance. + + Returns a instance. The returned instance may be a cached instance. + + + + + + + Factory class to create Durable Client to start works outside an azure function context. + + + + + Gets a using configuration from a instance. + + options containing the client configuration parameters. + Returns a instance. The returned instance may be a cached instance. + + + + Gets a using configuration from a instance. + + Returns a instance. The returned instance may be a cached instance. + Common functionality used by both @@ -1723,6 +1772,17 @@ Attribute used to bind a function parameter to a , , or instance. + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + durable client options + Optional. Gets or sets the name of the task hub in which the orchestration data lives. @@ -1744,6 +1804,11 @@ If no value exists there, then the default behavior is to use the standard `AzureWebJobsStorage` connection string for all storage usage. + + + Indicate if the client is External from the azure function where orchestrator functions are hosted. + + Returns a hash code for this attribute. @@ -3254,6 +3319,40 @@ Throws an exception if any of the settings of the storage provider are invalid. + + + Options used to bind a function parameter to a , , or instance. + + + + + Optional. Gets or sets the setting name for the app setting containing connection details used by this binding to connect + to instances of the storage provider other than the default one this application communicates with. + + The name of an app setting containing connection details. + + For Azure Storage the default behavior is to use the value of . + If no value exists there, then the default behavior is to use the standard `AzureWebJobsStorage` connection string for all storage usage. + + + + + Gets or sets the name of the task hub in which the orchestration data lives. + + The task hub used by this binding. + + The default behavior is to use the task hub name specified in . + If no value exists there, then a default value will be used. + + + + + Indicate if the client is External from the azure function where orchestrator functions are hosted. + + + Default is true. + + Configuration options for the Durable Task extension. @@ -3767,6 +3866,24 @@ The delegate to handle exception to determie if retries should proceed. + + + Connection string provider which resolves connection strings from the an standard application (Non WebJob). + + + + + Initializes a new instance of the class. + + A object provided by the application host. + + + + Looks up a connection string value given a name. + + The name of the connection string. + Returns the resolved connection string value. + Parameters for starting a new instance of an orchestration. diff --git a/src/WebJobs.Extensions.DurableTask/Microsoft.Azure.WebJobs.Extensions.DurableTask.xml b/src/WebJobs.Extensions.DurableTask/Microsoft.Azure.WebJobs.Extensions.DurableTask.xml index 39a4ee451..c2a3102dd 100644 --- a/src/WebJobs.Extensions.DurableTask/Microsoft.Azure.WebJobs.Extensions.DurableTask.xml +++ b/src/WebJobs.Extensions.DurableTask/Microsoft.Azure.WebJobs.Extensions.DurableTask.xml @@ -174,6 +174,55 @@ + + + Factory class to create Durable Client to start works outside an azure function context. + + + + + Initializes a new instance of the class. + + Default Options to Build Durable Clients. + The factory used to create orchestration service based on the configured storage provider. + The logger factory used for extension-specific logging and orchestration tracking. + The configuration options for this extension. + The factory used to create for message settings. + + + + Gets a using configuration from a instance. + + options containing the client configuration parameters. + Returns a instance. The returned instance may be a cached instance. + + + + Gets a using configuration from a instance. + + Returns a instance. The returned instance may be a cached instance. + + + + + + + Factory class to create Durable Client to start works outside an azure function context. + + + + + Gets a using configuration from a instance. + + options containing the client configuration parameters. + Returns a instance. The returned instance may be a cached instance. + + + + Gets a using configuration from a instance. + + Returns a instance. The returned instance may be a cached instance. + Common functionality used by both @@ -1728,6 +1777,17 @@ Attribute used to bind a function parameter to a , , or instance. + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + durable client options + Optional. Gets or sets the name of the task hub in which the orchestration data lives. @@ -1749,6 +1809,11 @@ If no value exists there, then the default behavior is to use the standard `AzureWebJobsStorage` connection string for all storage usage. + + + Indicate if the client is External from the azure function where orchestrator functions are hosted. + + Returns a hash code for this attribute. @@ -2097,6 +2162,21 @@ The to configure. Returns the provided . + + + Adds the Durable Task extension to the provided . + + The to configure. + Returns the provided . + + + + Adds the Durable Task extension to the provided . + + The to configure. + Populate default configurations of to create Durable Clients. + Returns the provided . + Adds the Durable Task extension to the provided . @@ -3294,6 +3374,40 @@ Throws an exception if any of the settings of the storage provider are invalid. + + + Options used to bind a function parameter to a , , or instance. + + + + + Optional. Gets or sets the setting name for the app setting containing connection details used by this binding to connect + to instances of the storage provider other than the default one this application communicates with. + + The name of an app setting containing connection details. + + For Azure Storage the default behavior is to use the value of . + If no value exists there, then the default behavior is to use the standard `AzureWebJobsStorage` connection string for all storage usage. + + + + + Gets or sets the name of the task hub in which the orchestration data lives. + + The task hub used by this binding. + + The default behavior is to use the task hub name specified in . + If no value exists there, then a default value will be used. + + + + + Indicate if the client is External from the azure function where orchestrator functions are hosted. + + + Default is true. + + Configuration options for the Durable Task extension. @@ -3807,6 +3921,24 @@ The delegate to handle exception to determie if retries should proceed. + + + Connection string provider which resolves connection strings from the an standard application (Non WebJob). + + + + + Initializes a new instance of the class. + + A object provided by the application host. + + + + Looks up a connection string value given a name. + + The name of the connection string. + Returns the resolved connection string value. + Parameters for starting a new instance of an orchestration. diff --git a/src/WebJobs.Extensions.DurableTask/Options/DurableClientOptions.cs b/src/WebJobs.Extensions.DurableTask/Options/DurableClientOptions.cs new file mode 100644 index 000000000..ad1f2c729 --- /dev/null +++ b/src/WebJobs.Extensions.DurableTask/Options/DurableClientOptions.cs @@ -0,0 +1,40 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Azure.WebJobs.Extensions.DurableTask.Options +{ + /// + /// Options used to bind a function parameter to a , , or instance. + /// + public class DurableClientOptions + { + /// + /// Optional. Gets or sets the setting name for the app setting containing connection details used by this binding to connect + /// to instances of the storage provider other than the default one this application communicates with. + /// + /// The name of an app setting containing connection details. + /// + /// For Azure Storage the default behavior is to use the value of . + /// If no value exists there, then the default behavior is to use the standard `AzureWebJobsStorage` connection string for all storage usage. + /// + public string ConnectionName { get; set; } + + /// + /// Gets or sets the name of the task hub in which the orchestration data lives. + /// + /// The task hub used by this binding. + /// + /// The default behavior is to use the task hub name specified in . + /// If no value exists there, then a default value will be used. + /// + public string TaskHub { get; set; } + + /// + /// Indicate if the client is External from the azure function where orchestrator functions are hosted. + /// + /// + /// Default is true. + /// + public bool IsExternalClient { get; set; } = true; + } +} \ No newline at end of file diff --git a/src/WebJobs.Extensions.DurableTask/Options/DurableTaskOptions.cs b/src/WebJobs.Extensions.DurableTask/Options/DurableTaskOptions.cs index 7ed2a3ecd..693eba34d 100644 --- a/src/WebJobs.Extensions.DurableTask/Options/DurableTaskOptions.cs +++ b/src/WebJobs.Extensions.DurableTask/Options/DurableTaskOptions.cs @@ -17,6 +17,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.DurableTask /// public class DurableTaskOptions { + internal const string DefaultHubName = "TestHubName"; private string originalHubName; private string resolvedHubName; private string defaultHubName; @@ -43,7 +44,7 @@ public string HubName { // "WEBSITE_SITE_NAME" is an environment variable used in Azure functions infrastructure. When running locally, this can be // specified in local.settings.json file to avoid being defaulted to "TestHubName" - this.resolvedHubName = Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME") ?? "TestHubName"; + this.resolvedHubName = Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME") ?? DefaultHubName; this.defaultHubName = this.resolvedHubName; } diff --git a/src/WebJobs.Extensions.DurableTask/StandardConnectionStringProvider.cs b/src/WebJobs.Extensions.DurableTask/StandardConnectionStringProvider.cs new file mode 100644 index 000000000..d488004c2 --- /dev/null +++ b/src/WebJobs.Extensions.DurableTask/StandardConnectionStringProvider.cs @@ -0,0 +1,34 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.Extensions.Configuration; + +namespace Microsoft.Azure.WebJobs.Extensions.DurableTask +{ + /// + /// Connection string provider which resolves connection strings from the an standard application (Non WebJob). + /// + public class StandardConnectionStringProvider : IConnectionStringResolver + { + private readonly IConfiguration configuration; + + /// + /// Initializes a new instance of the class. + /// + /// A object provided by the application host. + public StandardConnectionStringProvider(IConfiguration configuration) + { + this.configuration = configuration; + } + + /// + /// Looks up a connection string value given a name. + /// + /// The name of the connection string. + /// Returns the resolved connection string value. + public string Resolve(string connectionStringName) + { + return this.configuration[connectionStringName]; + } + } +} \ No newline at end of file