Made per instance queues temporary
This commit is contained in:
parent
7251c79f40
commit
3b66d7edbb
|
|
@ -1,8 +1,14 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Features.Abstractions;
|
||||
using Elsa.Features.Attributes;
|
||||
using Elsa.Features.Services;
|
||||
using Elsa.MassTransit.Consumers;
|
||||
using Elsa.MassTransit.Features;
|
||||
using Elsa.MassTransit.Options;
|
||||
using Elsa.Workflows.Contracts;
|
||||
using MassTransit;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Elsa.MassTransit.AzureServiceBus.Features;
|
||||
|
||||
|
|
@ -31,15 +37,34 @@ public class AzureServiceBusFeature : FeatureBase
|
|||
{
|
||||
massTransitFeature.BusConfigurator = configure =>
|
||||
{
|
||||
var tempConsumers = massTransitFeature.GetConsumers()
|
||||
.Where(c => c.IsTemporary)
|
||||
.ToList();
|
||||
|
||||
configure.AddServiceBusMessageScheduler();
|
||||
configure.AddConsumers(tempConsumers.Select(c => c.ConsumerType).ToArray());
|
||||
|
||||
configure.UsingAzureServiceBus((context, serviceBus) =>
|
||||
{
|
||||
var options = context.GetRequiredService<IOptions<MassTransitWorkflowDispatcherOptions>>().Value;
|
||||
var instanceNameRetriever = context.GetRequiredService<IInstanceNameRetriever>();
|
||||
|
||||
if (ConnectionString != null)
|
||||
serviceBus.Host(ConnectionString);
|
||||
|
||||
serviceBus.UseServiceBusMessageScheduler();
|
||||
ConfigureServiceBus?.Invoke(serviceBus);
|
||||
|
||||
foreach (var consumer in tempConsumers)
|
||||
{
|
||||
//Throw on no known name?
|
||||
serviceBus.ReceiveEndpoint($"{instanceNameRetriever.GetName()}-{consumer.Name}", configurator =>
|
||||
{
|
||||
configurator.AutoDeleteOnIdle = options.ShortTermQueueLifetime ?? TimeSpan.FromHours(1);
|
||||
configurator.ConcurrentMessageLimit = options.ConcurrentMessageLimit;
|
||||
configurator.ConfigureConsumer<DispatchCancelWorkflowsRequestConsumer>(context);
|
||||
});
|
||||
}
|
||||
|
||||
serviceBus.ConfigureEndpoints(context, new KebabCaseEndpointNameFormatter("Elsa", false));
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Features.Abstractions;
|
||||
using Elsa.Features.Attributes;
|
||||
using Elsa.Features.Services;
|
||||
using Elsa.MassTransit.Consumers;
|
||||
using Elsa.MassTransit.Features;
|
||||
using Elsa.MassTransit.Options;
|
||||
using Elsa.Workflows.Contracts;
|
||||
using MassTransit;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Elsa.MassTransit.RabbitMq.Features;
|
||||
|
||||
|
|
@ -32,18 +37,40 @@ public class RabbitMqServiceBusFeature : FeatureBase
|
|||
/// <inheritdoc />
|
||||
public override void Configure()
|
||||
{
|
||||
Module.Configure<MassTransitFeature>().BusConfigurator = configure =>
|
||||
Module.Configure<MassTransitFeature>(massTransitFeature =>
|
||||
{
|
||||
configure.UsingRabbitMq((context, serviceBus) =>
|
||||
massTransitFeature.BusConfigurator = configure =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ConnectionString))
|
||||
serviceBus.Host(ConnectionString);
|
||||
var tempConsumers = massTransitFeature.GetConsumers()
|
||||
.Where(c => c.IsTemporary)
|
||||
.ToList();
|
||||
|
||||
configure.AddConsumers(tempConsumers.Select(c => c.ConsumerType).ToArray());
|
||||
|
||||
configure.UsingRabbitMq((context, serviceBus) =>
|
||||
{
|
||||
var options = context.GetRequiredService<IOptions<MassTransitWorkflowDispatcherOptions>>().Value;
|
||||
var instanceNameRetriever = context.GetRequiredService<IInstanceNameRetriever>();
|
||||
|
||||
if (!string.IsNullOrEmpty(ConnectionString))
|
||||
serviceBus.Host(ConnectionString);
|
||||
|
||||
ConfigureServiceBus?.Invoke(serviceBus);
|
||||
ConfigureServiceBus?.Invoke(serviceBus);
|
||||
|
||||
foreach (var consumer in tempConsumers)
|
||||
{
|
||||
serviceBus.ReceiveEndpoint($"{instanceNameRetriever.GetName()}-{consumer.Name}", configurator =>
|
||||
{
|
||||
configurator.QueueExpiration = options.ShortTermQueueLifetime ?? TimeSpan.FromHours(1);
|
||||
configurator.ConcurrentMessageLimit = options.ConcurrentMessageLimit;
|
||||
configurator.ConfigureConsumer<DispatchCancelWorkflowsRequestConsumer>(context);
|
||||
});
|
||||
}
|
||||
|
||||
serviceBus.ConfigureEndpoints(context, new KebabCaseEndpointNameFormatter("Elsa", false));
|
||||
});
|
||||
};
|
||||
serviceBus.ConfigureEndpoints(context, new KebabCaseEndpointNameFormatter("Elsa", false));
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
using Elsa.MassTransit.Consumers;
|
||||
using Elsa.MassTransit.Options;
|
||||
using MassTransit;
|
||||
using MassTransit.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Elsa.MassTransit.ConsumerDefinitions;
|
||||
|
||||
/// <summary>
|
||||
/// Configures the endpoint for <see cref="DispatchCancelWorkflowsRequestConsumer"/>
|
||||
/// </summary>
|
||||
public class DispatchCancelWorkflowsRequestConsumerDefinition : ConsumerDefinition<DispatchCancelWorkflowsRequestConsumer>
|
||||
{
|
||||
private readonly IOptions<MassTransitWorkflowDispatcherOptions> _options;
|
||||
|
||||
/// <inheritdoc />
|
||||
public DispatchCancelWorkflowsRequestConsumerDefinition(IOptions<MassTransitWorkflowDispatcherOptions> options)
|
||||
{
|
||||
_options = options;
|
||||
ConcurrentMessageLimit = _options.Value.ConcurrentMessageLimit;
|
||||
EndpointName = "random-queue-name" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
this.EndpointDefinition!.IsTemporary = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void ConfigureConsumer(IReceiveEndpointConfigurator endpointConfigurator, IConsumerConfigurator<DispatchCancelWorkflowsRequestConsumer> consumerConfigurator, IRegistrationContext context)
|
||||
{
|
||||
endpointConfigurator.UseMessageRetry(r => r.Interval(5, 1000));
|
||||
endpointConfigurator.tem
|
||||
}
|
||||
}
|
||||
|
|
@ -18,27 +18,28 @@ public static class MassTransitFeatureExtensions
|
|||
/// <summary>
|
||||
/// Registers the specified type for MassTransit service bus consumer discovery.
|
||||
/// </summary>
|
||||
public static MassTransitFeature AddConsumer<T>(this MassTransitFeature feature) where T : IConsumer => feature.AddConsumer(typeof(T));
|
||||
public static MassTransitFeature AddConsumer<T>(this MassTransitFeature feature, string? name, bool isTemporary) where T : IConsumer => feature.AddConsumer(typeof(T), name, isTemporary);
|
||||
|
||||
/// <summary>
|
||||
/// Registers the specified type for MassTransit service bus consumer discovery.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The consumer type.</typeparam>
|
||||
/// <typeparam name="TDefinition">The consumer definition type.</typeparam>
|
||||
public static MassTransitFeature AddConsumer<T, TDefinition>(this MassTransitFeature feature)
|
||||
public static MassTransitFeature AddConsumer<T, TDefinition>(this MassTransitFeature feature, string? name, bool isTemporary)
|
||||
where T : IConsumer
|
||||
where TDefinition : IConsumerDefinition
|
||||
{
|
||||
return feature.AddConsumer(typeof(T), typeof(TDefinition));
|
||||
return feature.AddConsumer(typeof(T), name, isTemporary, typeof(TDefinition));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers the specified type for MassTransit service bus consumer discovery.
|
||||
/// </summary>
|
||||
public static MassTransitFeature AddConsumer(this MassTransitFeature feature, Type type, Type? consumerDefinitionType = default)
|
||||
public static MassTransitFeature AddConsumer(this MassTransitFeature feature, Type type, string? name, bool isTemporary,
|
||||
Type? consumerDefinitionType = default)
|
||||
{
|
||||
var types = feature.Module.Properties.GetOrAdd(ServiceBusConsumerTypesKey, () => new HashSet<ConsumerTypeDefinition>());
|
||||
types.Add(new ConsumerTypeDefinition(type, consumerDefinitionType));
|
||||
types.Add(new ConsumerTypeDefinition(type, consumerDefinitionType, name, isTemporary));
|
||||
return feature;
|
||||
}
|
||||
|
||||
|
|
@ -60,7 +61,7 @@ public static class MassTransitFeatureExtensions
|
|||
/// <summary>
|
||||
/// Returns all collected consumer types.
|
||||
/// </summary>
|
||||
internal static IEnumerable<ConsumerTypeDefinition> GetConsumers(this MassTransitFeature feature) => feature.Module.Properties.GetOrAdd(ServiceBusConsumerTypesKey, () => new HashSet<ConsumerTypeDefinition>());
|
||||
public static IEnumerable<ConsumerTypeDefinition> GetConsumers(this MassTransitFeature feature) => feature.Module.Properties.GetOrAdd(ServiceBusConsumerTypesKey, () => new HashSet<ConsumerTypeDefinition>());
|
||||
|
||||
/// <summary>
|
||||
/// Returns all collected message types.
|
||||
|
|
|
|||
|
|
@ -18,20 +18,20 @@ public static class ModuleExtensions
|
|||
/// <summary>
|
||||
/// Registers the specified consumer with MassTransit.
|
||||
/// </summary>
|
||||
public static IModule AddMassTransitConsumer<T>(this IModule module) where T : IConsumer
|
||||
public static IModule AddMassTransitConsumer<T>(this IModule module, string? name = null, bool isTemporary = false) where T : IConsumer
|
||||
{
|
||||
module.Configure<MassTransitFeature>(massTransit => massTransit.AddConsumer<T>());
|
||||
module.Configure<MassTransitFeature>(massTransit => massTransit.AddConsumer<T>(name, isTemporary));
|
||||
return module;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers the specified consumer and consumer definition with MassTransit.
|
||||
/// </summary>
|
||||
public static IModule AddMassTransitConsumer<T, TDefinition>(this IModule module)
|
||||
public static IModule AddMassTransitConsumer<T, TDefinition>(this IModule module, string? name = null, bool isTemporary = false)
|
||||
where T : IConsumer
|
||||
where TDefinition : IConsumerDefinition
|
||||
{
|
||||
module.Configure<MassTransitFeature>(massTransit => massTransit.AddConsumer<T, TDefinition>());
|
||||
module.Configure<MassTransitFeature>(massTransit => massTransit.AddConsumer<T, TDefinition>(name, isTemporary));
|
||||
return module;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public class MassTransitFeature : FeatureBase
|
|||
|
||||
Services.Configure<MassTransitWorkflowDispatcherOptions>(x => { });
|
||||
Services.AddActivityProvider<MassTransitActivityTypeProvider>();
|
||||
|
||||
|
||||
var busConfigurator = BusConfigurator ??= configure =>
|
||||
{
|
||||
configure.UsingInMemory((context, configurator) =>
|
||||
|
|
@ -92,7 +92,10 @@ public class MassTransitFeature : FeatureBase
|
|||
var workflowMessageConsumers = this.GetMessages().Select(x => new ConsumerTypeDefinition(workflowMessageConsumerType.MakeGenericType(x)));
|
||||
|
||||
// Concatenate the manually registered consumers with the workflow message consumers.
|
||||
var consumerTypeDefinitions = this.GetConsumers().Concat(workflowMessageConsumers).ToArray();
|
||||
var consumerTypeDefinitions = this.GetConsumers()
|
||||
//Temporary queues require implementation specific variables which will be handled in their respective projects
|
||||
.Where(c => c.IsTemporary == false)
|
||||
.Concat(workflowMessageConsumers).ToArray();
|
||||
|
||||
Services.AddMassTransit(bus =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public class MassTransitWorkflowDispatcherFeature : FeatureBase
|
|||
public override void Configure()
|
||||
{
|
||||
Module.AddMassTransitConsumer<DispatchWorkflowRequestConsumer, DispatchWorkflowRequestConsumerDefinition>();
|
||||
Module.AddMassTransitConsumer<DispatchCancelWorkflowsRequestConsumer, DispatchCancelWorkflowsRequestConsumerDefinition>();
|
||||
Module.AddMassTransitConsumer<DispatchCancelWorkflowsRequestConsumer>("dispatch-cancel-workflow", true);
|
||||
Module.Configure<WorkflowRuntimeFeature>(f => f.WorkflowDispatcher = sp => sp.GetRequiredService<MassTransitWorkflowDispatcher>());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
namespace Elsa.MassTransit.Models;
|
||||
|
||||
internal record ConsumerTypeDefinition(Type ConsumerType, Type? ConsumerDefinitionType = default);
|
||||
public record ConsumerTypeDefinition(Type ConsumerType, Type? ConsumerDefinitionType = default, string? Name = null, bool IsTemporary = false);
|
||||
|
|
@ -5,6 +5,8 @@ namespace Elsa.MassTransit.Options;
|
|||
/// Provides options to the <see cref="DispatchWorkflowRequestConsumerDefinition"/>
|
||||
public class MassTransitWorkflowDispatcherOptions
|
||||
{
|
||||
/// The TTL of queues that are seen as short lived (typically queues that are created per running instance).
|
||||
public TimeSpan? ShortTermQueueLifetime { get; set; }
|
||||
/// The number of concurrent messages to process.
|
||||
public int? ConcurrentMessageLimit { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
namespace Elsa.Workflows.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a name of the current instance.
|
||||
/// </summary>
|
||||
public interface IInstanceNameRetriever
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a name for the instance.
|
||||
/// </summary>
|
||||
public string GetName();
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using Elsa.Workflows.Contracts;
|
||||
|
||||
namespace Elsa.Workflows.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a randomly generated instance name.
|
||||
/// </summary>
|
||||
public class RandomInstanceNameRetriever : IInstanceNameRetriever
|
||||
{
|
||||
private readonly string _instanceName;
|
||||
|
||||
public RandomInstanceNameRetriever(RandomLongIdentityGenerator identityGenerator)
|
||||
{
|
||||
_instanceName = identityGenerator.GenerateId();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetName() => _instanceName;
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ using Elsa.Workflows.Runtime.Options;
|
|||
using Elsa.Workflows.Runtime.Providers;
|
||||
using Elsa.Workflows.Runtime.Services;
|
||||
using Elsa.Workflows.Runtime.Stores;
|
||||
using Elsa.Workflows.Services;
|
||||
using Medallion.Threading;
|
||||
using Medallion.Threading.FileSystem;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -98,6 +99,11 @@ public class WorkflowRuntimeFeature : FeatureBase
|
|||
/// </summary>
|
||||
public Func<IServiceProvider, IBackgroundActivityScheduler> BackgroundActivityScheduler { get; set; } = sp => ActivatorUtilities.CreateInstance<LocalBackgroundActivityScheduler>(sp);
|
||||
|
||||
/// <summary>
|
||||
/// A factory that instantiates an <see cref="IInstanceNameRetriever"/>.
|
||||
/// </summary>
|
||||
public Func<IServiceProvider, IInstanceNameRetriever> InstanceNameRetriever { get; set; } = sp => ActivatorUtilities.CreateInstance<RandomInstanceNameRetriever>(sp);
|
||||
|
||||
/// <summary>
|
||||
/// A delegate to configure the <see cref="DistributedLockingOptions"/>.
|
||||
/// </summary>
|
||||
|
|
@ -171,6 +177,8 @@ public class WorkflowRuntimeFeature : FeatureBase
|
|||
.AddScoped(WorkflowExecutionContextStore)
|
||||
.AddSingleton(RunTaskDispatcher)
|
||||
.AddSingleton(BackgroundActivityScheduler)
|
||||
.AddSingleton(InstanceNameRetriever)
|
||||
.AddSingleton<RandomLongIdentityGenerator>()
|
||||
.AddScoped<IBookmarkManager, DefaultBookmarkManager>()
|
||||
.AddScoped<IActivityExecutionManager, DefaultActivityExecutionManager>()
|
||||
.AddScoped<IActivityExecutionStatsService, ActivityExecutionStatsService>()
|
||||
|
|
|
|||
Loading…
Reference in a new issue