diff --git a/src/clients/Elsa.Api.Client/Extensions/DependencyInjectionExtensions.cs b/src/clients/Elsa.Api.Client/Extensions/DependencyInjectionExtensions.cs index 03c70efea..b80136e94 100644 --- a/src/clients/Elsa.Api.Client/Extensions/DependencyInjectionExtensions.cs +++ b/src/clients/Elsa.Api.Client/Extensions/DependencyInjectionExtensions.cs @@ -52,7 +52,6 @@ public static class DependencyInjectionExtensions { var builderOptions = new ElsaClientBuilderOptions(); configureClient.Invoke(builderOptions); - builderOptions.ConfigureHttpClientBuilder += builder => builder.AddHttpMessageHandler(sp => (DelegatingHandler)sp.GetRequiredService(builderOptions.AuthenticationHandler)); services.AddScoped(builderOptions.AuthenticationHandler); @@ -63,7 +62,19 @@ public static class DependencyInjectionExtensions options.ConfigureHttpClient = builderOptions.ConfigureHttpClient; options.ApiKey = builderOptions.ApiKey; }); + + var builderOptionsWithoutRetryPolicy = new ElsaClientBuilderOptions + { + ApiKey = builderOptions.ApiKey, + AuthenticationHandler = builderOptions.AuthenticationHandler, + BaseAddress = builderOptions.BaseAddress, + ConfigureHttpClient = builderOptions.ConfigureHttpClient, + ConfigureHttpClientBuilder = builderOptions.ConfigureHttpClientBuilder, + ConfigureRetryPolicy = null + }; + services.AddApi(builderOptions); + services.AddApi(builderOptionsWithoutRetryPolicy); services.AddApi(builderOptions); services.AddApi(builderOptions); services.AddApi(builderOptions); @@ -89,14 +100,20 @@ public static class DependencyInjectionExtensions public static void AddApi(this IServiceCollection services, ElsaClientBuilderOptions? httpClientBuilderOptions = default) where T : class { var builder = services.AddRefitClient(CreateRefitSettings, typeof(T).Name).ConfigureHttpClient(ConfigureElsaApiHttpClient); - httpClientBuilderOptions?.ConfigureHttpClientBuilder?.Invoke(builder); - - var retryCount = httpClientBuilderOptions?.TransientHttpErrorRetryCount ?? 0; - var sleepDurationProvider = httpClientBuilderOptions?.SleepDurationProvider ?? (retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); - if (retryCount > 0) - { - builder.AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(retryCount, sleepDurationProvider)); - } + httpClientBuilderOptions?.ConfigureHttpClientBuilder(builder); + httpClientBuilderOptions?.ConfigureRetryPolicy?.Invoke(builder); + } + + /// + /// Adds a refit client for the specified API type. + /// + /// The service collection. + /// An options object that can be used to configure the HTTP client builder. + /// The type representing the API. + public static void AddApiWithoutRetryPolicy(this IServiceCollection services, ElsaClientBuilderOptions? httpClientBuilderOptions = default) where T : class + { + var builder = services.AddRefitClient(CreateRefitSettings, typeof(T).Name).ConfigureHttpClient(ConfigureElsaApiHttpClient); + httpClientBuilderOptions?.ConfigureHttpClientBuilder(builder); } /// diff --git a/src/clients/Elsa.Api.Client/Options/ElsaClientBuilderOptions.cs b/src/clients/Elsa.Api.Client/Options/ElsaClientBuilderOptions.cs index 264fd0637..a7312eb60 100644 --- a/src/clients/Elsa.Api.Client/Options/ElsaClientBuilderOptions.cs +++ b/src/clients/Elsa.Api.Client/Options/ElsaClientBuilderOptions.cs @@ -1,5 +1,6 @@ using Elsa.Api.Client.HttpMessageHandlers; using Microsoft.Extensions.DependencyInjection; +using Polly; namespace Elsa.Api.Client.Options; @@ -35,21 +36,7 @@ public class ElsaClientBuilderOptions public Action ConfigureHttpClientBuilder { get; set; } = _ => { }; /// - /// Number of automatic retries for transient failures, including following categories: - /// - /// Network failures(as ) - /// HTTP 5XX status codes(server errors) - /// HTTP 408 status code(request timeout) - /// - /// Default value is 3. - /// Set the value to 0 to disable automatic retry. + /// Gets or sets a delegate that can be used to configure the retry policy. /// - public int TransientHttpErrorRetryCount { get; set; } = 3; - - /// - /// The function that provides the duration to wait for for each transient failure retry attempt. - /// This option is useless if TransientHttpErrorRetryCount is set to 0. - /// Default strategy is exponential backoff: TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)). - /// - public Func SleepDurationProvider = retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)); + public Action? ConfigureRetryPolicy { get; set; } = builder => builder.AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(3, attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)))); } \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IExecuteWorkflowApi.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IExecuteWorkflowApi.cs new file mode 100644 index 000000000..9b2ec493c --- /dev/null +++ b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IExecuteWorkflowApi.cs @@ -0,0 +1,32 @@ +using Elsa.Api.Client.Resources.WorkflowDefinitions.Requests; +using JetBrains.Annotations; +using Refit; + +namespace Elsa.Api.Client.Resources.WorkflowDefinitions.Contracts; + +/// +/// Represents a client for the workflow definitions API. +/// +[PublicAPI] +public interface IExecuteWorkflowApi +{ + /// + /// Executes a workflow definition. + /// + /// The definition ID of the workflow definition to execute. + /// An optional request containing options for executing the workflow definition. + /// An optional cancellation token. + /// A response containing information about the workflow instance that was created. + [Post("/workflow-definitions/{definitionId}/execute")] + Task ExecuteAsync(string definitionId, ExecuteWorkflowDefinitionRequest? request, CancellationToken cancellationToken = default); + + /// + /// Dispatches a request to execute the specified workflow definition. + /// + /// The definition ID of the workflow definition to dispatch request. + /// An optional request containing options for dispatching a request to execute the specified workflow definition. + /// An optional cancellation token. + /// A response containing information about the workflow instance that was created. + [Post("/workflow-definitions/{definitionId}/dispatch")] + Task DispatchAsync(string definitionId, DispatchWorkflowDefinitionRequest? request, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IWorkflowDefinitionsApi.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IWorkflowDefinitionsApi.cs index 73205909b..b165cec8f 100644 --- a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IWorkflowDefinitionsApi.cs +++ b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IWorkflowDefinitionsApi.cs @@ -196,24 +196,4 @@ public interface IWorkflowDefinitionsApi /// An optional cancellation token. [Post("/workflow-definitions/{definitionId}/revert/{version}")] Task RevertVersionAsync(string definitionId, int version, CancellationToken cancellationToken = default); - - /// - /// Executes a workflow definition. - /// - /// The definition ID of the workflow definition to execute. - /// An optional request containing options for executing the workflow definition. - /// An optional cancellation token. - /// A response containing information about the workflow instance that was created. - [Post("/workflow-definitions/{definitionId}/execute")] - Task ExecuteAsync(string definitionId, ExecuteWorkflowDefinitionRequest? request, CancellationToken cancellationToken = default); - - /// - /// Dispatches a request to execute the specified workflow definition. - /// - /// The definition ID of the workflow definition to dispatch request. - /// An optional request containing options for dispatching a request to execute the specified workflow definition. - /// An optional cancellation token. - /// A response containing information about the workflow instance that was created. - [Post("/workflow-definitions/{definitionId}/dispatch")] - Task DispatchAsync(string definitionId, DispatchWorkflowDefinitionRequest? request, CancellationToken cancellationToken = default); } \ No newline at end of file