diff --git a/examples/ConductorSharp.ApiEnabled/Controllers/WorkflowController.cs b/examples/ConductorSharp.ApiEnabled/Controllers/WorkflowController.cs index 2adf5f95..0d22ed89 100644 --- a/examples/ConductorSharp.ApiEnabled/Controllers/WorkflowController.cs +++ b/examples/ConductorSharp.ApiEnabled/Controllers/WorkflowController.cs @@ -12,13 +12,20 @@ public class WorkflowController : ControllerBase private readonly IMetadataService _metadataService; private readonly IWorkflowService _workflowService; private readonly ITaskService _taskService; + private readonly IMetadataService _alternateMetadataService; private const string NotificationWorfklowName = "NOTIFICATION_send_to_customer"; - public WorkflowController(IMetadataService metadataService, IWorkflowService workflowService, ITaskService taskService) + public WorkflowController( + IMetadataService metadataService, + IWorkflowService workflowService, + ITaskService taskService, + [FromKeyedServices("Alternate")] IMetadataService alternateMetadataService + ) { _metadataService = metadataService; _workflowService = workflowService; _taskService = taskService; + _alternateMetadataService = alternateMetadataService; } [HttpGet("get-workflows")] @@ -45,4 +52,12 @@ await _workflowService.StartAsync( Input = new Dictionary { { "task_to_execute", "CUSTOMER_get" }, { "customer_id", request.CustomerId } } } ); + + [HttpGet("get-workflows/{discriminator}")] + public async Task> GetRegisteredWorkflows(string discriminator) => + discriminator switch + { + "alternate" => await _alternateMetadataService.ListWorkflowsAsync(), + _ => await _metadataService.ListWorkflowsAsync() + }; } diff --git a/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs b/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs index 26bd0e93..ce5f0827 100644 --- a/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs +++ b/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs @@ -11,6 +11,7 @@ public static IServiceCollection ConfigureApiEnabled(this IServiceCollection hos { hostBuilder .AddConductorSharp(baseUrl: configuration.GetValue("Conductor:BaseUrl")) + .AddAlternateClient(baseUrl: configuration.GetValue("Conductor:AlternateUrl"), "Alternate", "api/workflow", true) .AddExecutionManager( maxConcurrentWorkers: configuration.GetValue("Conductor:MaxConcurrentWorkers"), sleepInterval: configuration.GetValue("Conductor:SleepInterval"), diff --git a/examples/ConductorSharp.ApiEnabled/appsettings.json b/examples/ConductorSharp.ApiEnabled/appsettings.json index dc040a32..5a86f767 100644 --- a/examples/ConductorSharp.ApiEnabled/appsettings.json +++ b/examples/ConductorSharp.ApiEnabled/appsettings.json @@ -1,6 +1,7 @@ { "Conductor": { "BaseUrl": "http://localhost:8080", + "AlternateUrl": "https://fm-dev.10.7.6.124.nip.io", "LongPollInterval": 100, "MaxConcurrentWorkers": 10, "SleepInterval": 500 diff --git a/src/ConductorSharp.Client/ConductorSharp.Client.csproj b/src/ConductorSharp.Client/ConductorSharp.Client.csproj index 33e445c6..f4be8a7a 100644 --- a/src/ConductorSharp.Client/ConductorSharp.Client.csproj +++ b/src/ConductorSharp.Client/ConductorSharp.Client.csproj @@ -6,7 +6,7 @@ Codaxy Codaxy ConductorSharp.Client - 3.0.1-beta8 + 3.0.1-beta9 Client library for Netflix Conductor, with some additional quality of life features. https://github.com/codaxy/conductor-sharp netflix;conductor @@ -17,6 +17,7 @@ + diff --git a/src/ConductorSharp.Client/Service/AdminService.cs b/src/ConductorSharp.Client/Service/AdminService.cs index acaab00f..d0246cde 100644 --- a/src/ConductorSharp.Client/Service/AdminService.cs +++ b/src/ConductorSharp.Client/Service/AdminService.cs @@ -2,25 +2,27 @@ namespace ConductorSharp.Client.Service { - public class AdminService(ConductorClient client) : IAdminService + public class AdminService(IHttpClientFactory httpClientFactory, string clientName) : IAdminService { + private readonly ConductorClient _client = new(httpClientFactory.CreateClient(clientName)); + public async Task QueueRunningWorkflowsForSweepAsync(string workflowId, CancellationToken cancellationToken = default) => - await client.RequeueSweepAsync(workflowId, cancellationToken); + await _client.RequeueSweepAsync(workflowId, cancellationToken); public async Task VerifyAndRepairWorkflowConsistencyAsync(string workflowId, CancellationToken cancellationToken = default) => - await client.VerifyAndRepairWorkflowConsistencyAsync(workflowId, cancellationToken); + await _client.VerifyAndRepairWorkflowConsistencyAsync(workflowId, cancellationToken); public async Task> ListPendingTasksAsync( string taskType, int? start, int? count, CancellationToken cancellationToken = default - ) => await client.ViewAsync(taskType, start, count, cancellationToken); + ) => await _client.ViewAsync(taskType, start, count, cancellationToken); public async Task> GetEventQueueMapAsync(bool? verbose, CancellationToken cancellationToken = default) => - await client.GetEventQueuesAsync(verbose, cancellationToken); + await _client.GetEventQueuesAsync(verbose, cancellationToken); public async Task> GetConfigMapAsync(CancellationToken cancellationToken = default) => - await client.GetAllConfigAsync(cancellationToken); + await _client.GetAllConfigAsync(cancellationToken); } } diff --git a/src/ConductorSharp.Client/Service/EventService.cs b/src/ConductorSharp.Client/Service/EventService.cs index 15238fc5..dd53c871 100644 --- a/src/ConductorSharp.Client/Service/EventService.cs +++ b/src/ConductorSharp.Client/Service/EventService.cs @@ -3,24 +3,26 @@ namespace ConductorSharp.Client.Service { - public class EventService(ConductorClient client) : IEventService + public class EventService(IHttpClientFactory httpClientFactory, string clientName) : IEventService { + private readonly ConductorClient _client = new(httpClientFactory.CreateClient(clientName)); + public async Task> ListAsync(CancellationToken cancellationToken = default) => - await client.GetEventHandlersAsync(cancellationToken); + await _client.GetEventHandlersAsync(cancellationToken); public async Task UpdateAsync(EventHandler eventHandler, CancellationToken cancellationToken = default) => - await client.UpdateEventHandlerAsync(eventHandler, cancellationToken); + await _client.UpdateEventHandlerAsync(eventHandler, cancellationToken); public async Task AddAsync(EventHandler eventHandler, CancellationToken cancellationToken = default) => - await client.AddEventHandlerAsync(eventHandler, cancellationToken); + await _client.AddEventHandlerAsync(eventHandler, cancellationToken); public async Task> ListForEventAsync( string @event, bool? activeOnly = null, CancellationToken cancellationToken = default - ) => await client.GetEventHandlersForEventAsync(@event, activeOnly, cancellationToken); + ) => await _client.GetEventHandlersForEventAsync(@event, activeOnly, cancellationToken); public async Task RemoveEventHandlerStatusAsync(string name, CancellationToken cancellationToken = default) => - await client.RemoveEventHandlerStatusAsync(name, cancellationToken); + await _client.RemoveEventHandlerStatusAsync(name, cancellationToken); } } diff --git a/src/ConductorSharp.Client/Service/ExternalPayloadService.cs b/src/ConductorSharp.Client/Service/ExternalPayloadService.cs index 1b30b584..2f90972f 100644 --- a/src/ConductorSharp.Client/Service/ExternalPayloadService.cs +++ b/src/ConductorSharp.Client/Service/ExternalPayloadService.cs @@ -1,10 +1,13 @@ -using ConductorSharp.Client.Generated; +using System.Net.Http; +using ConductorSharp.Client.Generated; namespace ConductorSharp.Client.Service { - public class ExternalPayloadService(ConductorClient client) : IExternalPayloadService + public class ExternalPayloadService(IHttpClientFactory httpClientFactory, string clientName) : IExternalPayloadService { + private readonly ConductorClient _client = new(httpClientFactory.CreateClient(clientName)); + public async Task GetExternalStorageDataAsync(string externalPayloadPath, CancellationToken cancellationToken = default) => - await client.GetExternalStorageDataAsync(externalPayloadPath, cancellationToken); + await _client.GetExternalStorageDataAsync(externalPayloadPath, cancellationToken); } } diff --git a/src/ConductorSharp.Client/Service/HealthService.cs b/src/ConductorSharp.Client/Service/HealthService.cs index 48d8cec9..c3941f6a 100644 --- a/src/ConductorSharp.Client/Service/HealthService.cs +++ b/src/ConductorSharp.Client/Service/HealthService.cs @@ -1,12 +1,13 @@ -using ConductorSharp.Client.Generated; +using System.Net.Http; +using ConductorSharp.Client.Generated; namespace ConductorSharp.Client.Service { - public class HealthService(ConductorClient client) : IHealthService + public class HealthService(IHttpClientFactory httpClientFactory, string clientName) : IHealthService { - private readonly ConductorClient _conductorClient = client; + private readonly ConductorClient _client = new(httpClientFactory.CreateClient(clientName)); public async Task CheckHealthAsync(CancellationToken cancellationToken = default) => - await _conductorClient.DoCheckAsync(cancellationToken); + await _client.DoCheckAsync(cancellationToken); } } diff --git a/src/ConductorSharp.Client/Service/MetadataService.cs b/src/ConductorSharp.Client/Service/MetadataService.cs index cf6db353..1dd0d041 100644 --- a/src/ConductorSharp.Client/Service/MetadataService.cs +++ b/src/ConductorSharp.Client/Service/MetadataService.cs @@ -2,45 +2,47 @@ namespace ConductorSharp.Client.Service { - public class MetadataService(ConductorClient client) : IMetadataService + public class MetadataService(IHttpClientFactory httpClientFactory, string clientName) : IMetadataService { + private readonly ConductorClient _client = new(httpClientFactory.CreateClient(clientName)); + public async Task> ListWorkflowsAsync(CancellationToken cancellationToken = default) => - await client.GetAllAsync(cancellationToken); + await _client.GetAllAsync(cancellationToken); public async Task UpdateWorkflowsAsync(IEnumerable workflows, CancellationToken cancellationToken = default) => - await client.UpdateAsync(workflows, cancellationToken); + await _client.UpdateAsync(workflows, cancellationToken); public async Task AddWorkflowAsync(WorkflowDef workflowDef, CancellationToken cancellationToken = default) => - await client.CreateAsync(workflowDef, cancellationToken); + await _client.CreateAsync(workflowDef, cancellationToken); public async Task> ListTasksAsync(CancellationToken cancellationToken = default) => - await client.GetTaskDefsAsync(cancellationToken); + await _client.GetTaskDefsAsync(cancellationToken); public async Task AddTaskAsync(TaskDef taskDef, CancellationToken cancellationToken = default) => - await client.RegisterTaskDefAsync(taskDef, cancellationToken); + await _client.RegisterTaskDefAsync(taskDef, cancellationToken); public async Task AddTasksAsync(IEnumerable taskDefs, CancellationToken cancellationToken = default) => - await client.RegisterTaskDef_1Async(taskDefs, cancellationToken); + await _client.RegisterTaskDef_1Async(taskDefs, cancellationToken); public async Task ValidateWorkflowAsync(WorkflowDef workflowDef, CancellationToken cancellationToken = default) => - await client.ValidateAsync(workflowDef, cancellationToken); + await _client.ValidateAsync(workflowDef, cancellationToken); public async Task GetWorkflowAsync(string name, int? version = null, CancellationToken cancellationToken = default) => - await client.GetAsync(name, version, cancellationToken); + await _client.GetAsync(name, version, cancellationToken); public async Task> GetWorkflowNamesAndVersionsAsync(CancellationToken cancellationToken = default) => - await client.GetWorkflowNamesAndVersionsAsync(cancellationToken); + await _client.GetWorkflowNamesAndVersionsAsync(cancellationToken); public async Task> GetAllWorkflowsWithLatestVersionsAsync(CancellationToken cancellationToken = default) => - await client.GetAllWorkflowsWithLatestVersionsAsync(cancellationToken); + await _client.GetAllWorkflowsWithLatestVersionsAsync(cancellationToken); public async Task GetTaskAsync(string taskType, CancellationToken cancellationToken = default) => - await client.GetTaskDefAsync(taskType, cancellationToken); + await _client.GetTaskDefAsync(taskType, cancellationToken); public async Task DeleteTaskAsync(string taskType, CancellationToken cancellationToken = default) => - await client.UnregisterTaskDefAsync(taskType, cancellationToken); + await _client.UnregisterTaskDefAsync(taskType, cancellationToken); public async Task DeleteWorkflowAsync(string name, int version, CancellationToken cancellationToken = default) => - await client.UnregisterWorkflowDefAsync(name, version, cancellationToken); + await _client.UnregisterWorkflowDefAsync(name, version, cancellationToken); } } diff --git a/src/ConductorSharp.Client/Service/QueueAdminService.cs b/src/ConductorSharp.Client/Service/QueueAdminService.cs index f45fa488..872c1c6b 100644 --- a/src/ConductorSharp.Client/Service/QueueAdminService.cs +++ b/src/ConductorSharp.Client/Service/QueueAdminService.cs @@ -1,16 +1,19 @@ -using ConductorSharp.Client.Generated; +using System.Net.Http; +using ConductorSharp.Client.Generated; namespace ConductorSharp.Client.Service; -public class QueueAdminService(ConductorClient client) : IQueueAdminService +public class QueueAdminService(IHttpClientFactory httpClientFactory, string clientName) : IQueueAdminService { + private readonly ConductorClient _client = new(httpClientFactory.CreateClient(clientName)); + public async Task MarkWaitTaskCompletedAsync( string workflowId, string taskRefName, Status2 status, IDictionary output, CancellationToken cancellationToken = default - ) => await client.Update_1Async(workflowId, taskRefName, status, output, cancellationToken); + ) => await _client.Update_1Async(workflowId, taskRefName, status, output, cancellationToken); public async Task MarkWaitTaskCompletedAsync( string workflowId, @@ -18,11 +21,11 @@ public async Task MarkWaitTaskCompletedAsync( Generated.TaskStatus status, IDictionary output, CancellationToken cancellationToken = default - ) => await client.UpdateByTaskIdAsync(workflowId, taskId, status, output, cancellationToken); + ) => await _client.UpdateByTaskIdAsync(workflowId, taskId, status, output, cancellationToken); public async Task> GetQueueLengthAsync(CancellationToken cancellationToken = default) => - await client.Size_1Async(cancellationToken); + await _client.Size_1Async(cancellationToken); public async Task> GetQueueNamesAsync(CancellationToken cancellationToken = default) => - await client.NamesAsync(cancellationToken); + await _client.NamesAsync(cancellationToken); } diff --git a/src/ConductorSharp.Client/Service/TaskService.cs b/src/ConductorSharp.Client/Service/TaskService.cs index b11b12bb..90291128 100644 --- a/src/ConductorSharp.Client/Service/TaskService.cs +++ b/src/ConductorSharp.Client/Service/TaskService.cs @@ -2,9 +2,9 @@ namespace ConductorSharp.Client.Service { - public class TaskService(ConductorClient client) : ITaskService + public class TaskService(IHttpClientFactory httpClientFactory, string clientName) : ITaskService { - private readonly ConductorClient _client = client; + private readonly ConductorClient _client = new(httpClientFactory.CreateClient(clientName)); public async Task UpdateAsync(TaskResult updateRequest, CancellationToken cancellationToken = default) => await _client.UpdateTaskAsync(updateRequest, cancellationToken); diff --git a/src/ConductorSharp.Client/Service/WorkflowBulkService.cs b/src/ConductorSharp.Client/Service/WorkflowBulkService.cs index 3feba681..1b99adb5 100644 --- a/src/ConductorSharp.Client/Service/WorkflowBulkService.cs +++ b/src/ConductorSharp.Client/Service/WorkflowBulkService.cs @@ -2,26 +2,28 @@ namespace ConductorSharp.Client.Service; -public class WorkflowBulkService(ConductorClient client) : IWorkflowBulkService +public class WorkflowBulkService(IHttpClientFactory httpClientFactory, string clientName) : IWorkflowBulkService { + private readonly ConductorClient _client = new(httpClientFactory.CreateClient(clientName)); + public async Task ResumeAsync(IEnumerable workflowIds, CancellationToken cancellationToken = default) => - await client.ResumeWorkflow_1Async(workflowIds, cancellationToken); + await _client.ResumeWorkflow_1Async(workflowIds, cancellationToken); public async Task PauseAsync(IEnumerable workflowIds, CancellationToken cancellationToken = default) => - await client.PauseWorkflow_1Async(workflowIds, cancellationToken); + await _client.PauseWorkflow_1Async(workflowIds, cancellationToken); public async Task TerminateAsync( IEnumerable worklowIds, string? reason = null, CancellationToken cancellationToken = default - ) => await client.TerminateAsync(reason, worklowIds, cancellationToken); + ) => await _client.TerminateAsync(reason, worklowIds, cancellationToken); public async Task RetryAsync(IEnumerable workflowIds, CancellationToken cancellationToken = default) => - await client.Retry_1Async(workflowIds, cancellationToken); + await _client.Retry_1Async(workflowIds, cancellationToken); public async Task RestartAsync( IEnumerable workflowIds, bool? useLatestDefinition = null, CancellationToken cancellationToken = default - ) => await client.Restart_1Async(useLatestDefinition, workflowIds, cancellationToken); + ) => await _client.Restart_1Async(useLatestDefinition, workflowIds, cancellationToken); } diff --git a/src/ConductorSharp.Client/Service/WorkflowService.cs b/src/ConductorSharp.Client/Service/WorkflowService.cs index e25380f6..08c179d1 100644 --- a/src/ConductorSharp.Client/Service/WorkflowService.cs +++ b/src/ConductorSharp.Client/Service/WorkflowService.cs @@ -1,10 +1,11 @@ -using ConductorSharp.Client.Generated; +using System.Net.Http; +using ConductorSharp.Client.Generated; namespace ConductorSharp.Client.Service { - public class WorkflowService(ConductorClient client) : IWorkflowService + public class WorkflowService(IHttpClientFactory httpClientFactory, string clientName) : IWorkflowService { - private readonly ConductorClient _client = client; + private readonly ConductorClient _client = new(httpClientFactory.CreateClient(clientName)); /// /// Skips a given task from a current running workflow diff --git a/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj b/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj index 20a19cb4..4bdf038a 100644 --- a/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj +++ b/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj @@ -6,7 +6,7 @@ Codaxy Codaxy ConductorSharp.Engine - 3.0.1-beta8 + 3.0.1-beta9 Client library for Netflix Conductor, with some additional quality of life features. https://github.com/codaxy/conductor-sharp netflix;conductor diff --git a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs index d71f379c..63d09cf1 100644 --- a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs @@ -1,5 +1,7 @@ using System; +using System.Net.Http; using System.Reflection; +using ConductorSharp.Client.Service; using ConductorSharp.Engine.Behaviors; using ConductorSharp.Engine.Health; using ConductorSharp.Engine.Interface; @@ -86,5 +88,31 @@ public IConductorSharpBuilder SetBuildConfiguration(BuildConfiguration buildConf Builder.AddSingleton(buildConfiguration); return this; } + + public IConductorSharpBuilder AddAlternateClient(string baseUrl, string key, string apiPath = "api", bool ignoreInvalidCertificate = false) + { + var clientBuilder = builder + .AddHttpClient(key, client => client.BaseAddress = new(baseUrl)) + .AddHttpMessageHandler(() => new ApiPathOverrideHttpHandler(apiPath)); + + if (ignoreInvalidCertificate) + { + clientBuilder.ConfigurePrimaryHttpMessageHandler( + () => new HttpClientHandler { ServerCertificateCustomValidationCallback = (_, _, _, _) => true } + ); + } + + builder.AddKeyedTransient(key, ((sp, _) => new(sp.GetService(), key))); + builder.AddKeyedTransient(key, (sp, _) => new(sp.GetService(), key)); + builder.AddKeyedTransient(key, (sp, _) => new(sp.GetService(), key)); + builder.AddKeyedTransient(key, (sp, _) => new(sp.GetService(), key)); + builder.AddKeyedTransient(key, (sp, _) => new(sp.GetService(), key)); + builder.AddKeyedTransient(key, (sp, _) => new(sp.GetService(), key)); + builder.AddKeyedTransient(key, (sp, _) => new(sp.GetService(), key)); + builder.AddKeyedTransient(key, (sp, _) => new(sp.GetService(), key)); + builder.AddKeyedTransient(key, (sp, _) => new(sp.GetService(), key)); + + return this; + } } } diff --git a/src/ConductorSharp.Engine/Extensions/ContainerBuilderExtensions.cs b/src/ConductorSharp.Engine/Extensions/ContainerBuilderExtensions.cs index 6466bd9f..f236fda4 100644 --- a/src/ConductorSharp.Engine/Extensions/ContainerBuilderExtensions.cs +++ b/src/ConductorSharp.Engine/Extensions/ContainerBuilderExtensions.cs @@ -1,9 +1,11 @@ using System; using System.Net.Http; +using System.Reflection; using ConductorSharp.Client.Generated; using ConductorSharp.Client.Service; using ConductorSharp.Engine.Builders; using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; using ConductorSharp.Engine.Util.Builders; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -13,19 +15,35 @@ namespace ConductorSharp.Engine.Extensions { public static class ContainerBuilderExtensions { - public static IConductorSharpBuilder AddConductorSharp(this IServiceCollection builder, string baseUrl) + private const string DefaultClientName = "ConductorSharp.Client.DefaultHttpClient"; + + public static IConductorSharpBuilder AddConductorSharp( + this IServiceCollection builder, + string baseUrl, + string apiPath = "api", + bool ignoreInvalidCertificate = false + ) { - builder.AddTransient(); - builder.AddHttpClient().ConfigureHttpClient(client => client.BaseAddress = new Uri(baseUrl)); - builder.AddTransient(); - builder.AddTransient(); - builder.AddTransient(); - builder.AddTransient(); - builder.AddTransient(); - builder.AddTransient(); - builder.AddTransient(); - builder.AddTransient(); - builder.AddTransient(); + var clientBuilder = builder + .AddHttpClient(DefaultClientName, client => client.BaseAddress = new(baseUrl)) + .AddHttpMessageHandler(() => new ApiPathOverrideHttpHandler(apiPath)); + + if (ignoreInvalidCertificate) + { + clientBuilder.ConfigurePrimaryHttpMessageHandler( + () => new HttpClientHandler { ServerCertificateCustomValidationCallback = (_, _, _, _) => true } + ); + } + + builder.AddTransient(sp => new(sp.GetService(), DefaultClientName)); + builder.AddTransient(sp => new(sp.GetService(), DefaultClientName)); + builder.AddTransient(sp => new(sp.GetService(), DefaultClientName)); + builder.AddTransient(sp => new(sp.GetService(), DefaultClientName)); + builder.AddTransient(sp => new(sp.GetService(), DefaultClientName)); + builder.AddTransient(sp => new(sp.GetService(), DefaultClientName)); + builder.AddTransient(sp => new(sp.GetService(), DefaultClientName)); + builder.AddTransient(sp => new(sp.GetService(), DefaultClientName)); + builder.AddTransient(sp => new(sp.GetService(), DefaultClientName)); builder.AddSingleton(new BuildConfiguration()); builder.AddSingleton(); diff --git a/src/ConductorSharp.Engine/Extensions/IConductorSharpBuilder.cs b/src/ConductorSharp.Engine/Extensions/IConductorSharpBuilder.cs index 56ef342a..c381b887 100644 --- a/src/ConductorSharp.Engine/Extensions/IConductorSharpBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/IConductorSharpBuilder.cs @@ -1,8 +1,8 @@ -using ConductorSharp.Engine.Util.Builders; -using System; +using System; using System.Collections.Generic; using System.Reflection; using System.Text; +using ConductorSharp.Engine.Util.Builders; namespace ConductorSharp.Engine.Extensions { @@ -16,5 +16,6 @@ IExecutionManagerBuilder AddExecutionManager( params Assembly[] handlerAssemblies ); IConductorSharpBuilder SetBuildConfiguration(BuildConfiguration buildConfiguration); + IConductorSharpBuilder AddAlternateClient(string baseUrl, string key, string apiPath = "api", bool ignoreInvalidCertificate = false); } } diff --git a/src/ConductorSharp.Engine/Util/ApiPathOverrideHttpHandler.cs b/src/ConductorSharp.Engine/Util/ApiPathOverrideHttpHandler.cs new file mode 100644 index 00000000..0e8d5f65 --- /dev/null +++ b/src/ConductorSharp.Engine/Util/ApiPathOverrideHttpHandler.cs @@ -0,0 +1,26 @@ +using System; +using System.Net.Http; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +namespace ConductorSharp.Engine.Util +{ + internal class ApiPathOverrideHttpHandler(string apiPath) : DelegatingHandler + { + private readonly Regex _pathRegex = new("api"); + + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var uri = request.RequestUri!; + request.RequestUri = OverridePath(uri); + return base.SendAsync(request, cancellationToken); + } + + private Uri OverridePath(Uri uri) + { + var overridenPathAndQuery = _pathRegex.Replace(uri.PathAndQuery, apiPath, 1); + return new Uri(new Uri(uri.Scheme + "://" + uri.Authority), overridenPathAndQuery); + } + } +} diff --git a/src/ConductorSharp.Patterns/ConductorSharp.Patterns.csproj b/src/ConductorSharp.Patterns/ConductorSharp.Patterns.csproj index 80d35a25..b5bf79a8 100644 --- a/src/ConductorSharp.Patterns/ConductorSharp.Patterns.csproj +++ b/src/ConductorSharp.Patterns/ConductorSharp.Patterns.csproj @@ -7,7 +7,7 @@ False Codaxy Codaxy - 3.0.1-beta8 + 3.0.1-beta9 diff --git a/test/ConductorSharp.Engine.Tests/Unit/ContainerBuilderTests.cs b/test/ConductorSharp.Engine.Tests/Unit/ContainerBuilderTests.cs index bb1d2be0..75669f41 100644 --- a/test/ConductorSharp.Engine.Tests/Unit/ContainerBuilderTests.cs +++ b/test/ConductorSharp.Engine.Tests/Unit/ContainerBuilderTests.cs @@ -1,4 +1,5 @@ using ConductorSharp.Client.Generated; +using ConductorSharp.Client.Service; using ConductorSharp.Engine.Extensions; using ConductorSharp.Engine.Tests.Samples.Workflows; using ConductorSharp.Engine.Tests.Util; @@ -96,5 +97,65 @@ public void FailsToResolveWorkflowDependencies() var container = builder.BuildServiceProvider(); Assert.Throws(() => container.GetRequiredService>()); } + + [Fact] + public void SuccesfullyResolveClients() + { + const string alternateClient = "Alternate"; + var builder = new ServiceCollection(); + builder.AddConductorSharp(baseUrl: "http://empty/empty").AddAlternateClient("http://alternate/alternate", alternateClient); + + var container = builder.BuildServiceProvider(); + + var adminService = container.GetService(); + var eventService = container.GetService(); + var externalPayloadService = container.GetService(); + var queueAdminService = container.GetService(); + var workflowBulkService = container.GetService(); + var taskService = container.GetService(); + var healthService = container.GetService(); + var metadataService = container.GetService(); + var workflowService = container.GetService(); + + var alternateAdminService = container.GetKeyedService(alternateClient); + var alternateEventService = container.GetKeyedService(alternateClient); + var alternateExternalPayloadService = container.GetKeyedService(alternateClient); + var alternateQueueAdminService = container.GetKeyedService(alternateClient); + var alternateWorkflowBulkService = container.GetKeyedService(alternateClient); + var alternateTaskService = container.GetKeyedService(alternateClient); + var alternateHealthService = container.GetKeyedService(alternateClient); + var alternateMetadataService = container.GetKeyedService(alternateClient); + var alternateWorkflowService = container.GetKeyedService(alternateClient); + + Assert.NotNull(adminService); + Assert.NotNull(eventService); + Assert.NotNull(externalPayloadService); + Assert.NotNull(queueAdminService); + Assert.NotNull(workflowBulkService); + Assert.NotNull(taskService); + Assert.NotNull(healthService); + Assert.NotNull(metadataService); + Assert.NotNull(workflowService); + + Assert.NotNull(alternateAdminService); + Assert.NotNull(alternateEventService); + Assert.NotNull(alternateExternalPayloadService); + Assert.NotNull(alternateQueueAdminService); + Assert.NotNull(alternateWorkflowBulkService); + Assert.NotNull(alternateTaskService); + Assert.NotNull(alternateHealthService); + Assert.NotNull(alternateMetadataService); + Assert.NotNull(alternateWorkflowService); + + Assert.NotEqual(adminService, alternateAdminService); + Assert.NotEqual(eventService, alternateEventService); + Assert.NotEqual(externalPayloadService, alternateExternalPayloadService); + Assert.NotEqual(queueAdminService, alternateQueueAdminService); + Assert.NotEqual(workflowBulkService, alternateWorkflowBulkService); + Assert.NotEqual(taskService, alternateTaskService); + Assert.NotEqual(healthService, alternateHealthService); + Assert.NotEqual(metadataService, alternateMetadataService); + Assert.NotEqual(workflowService, alternateWorkflowService); + } } }