Added exchange name property, removed auto delete for bindings (#2622)

Added Exchange Name property to give ability to subscribe/publish to specific exchange. Removed binding auto-delete to preserve binding in case of disconnect.  Added RabbitMQ connection string format to connection string property tooltip.
This commit is contained in:
Konstantins Vedenins 2021-12-22 14:52:56 +02:00 committed by GitHub
parent 5c6dc307f5
commit 2a9c8d0b7e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 101 additions and 21 deletions

View file

@ -6,6 +6,7 @@ namespace Elsa.Activities.RabbitMq
public interface IRabbitMqActivity : IActivity
{
string ConnectionString { get; set; }
string ExchangeName { get; set; }
string RoutingKey { get; set; }
Dictionary<string, string> Headers { get; set; }
}

View file

@ -28,21 +28,27 @@ namespace Elsa.Activities.RabbitMq
}
[ActivityInput(
Hint = "Routing Key",
Hint = "Exchange to listen to",
Order = 1,
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
public string ExchangeName { get; set; } = default!;
[ActivityInput(
Hint = "Routing Key",
Order = 2,
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
public string RoutingKey { get; set; } = default!;
[ActivityInput(
Hint = "List of headers that should be present in the message",
Order = 2,
Order = 3,
UIHint = ActivityInputUIHints.Dictionary,
DefaultSyntax = SyntaxNames.Json,
SupportedSyntaxes = new[] { SyntaxNames.Json })]
public Dictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
[ActivityInput(
Hint = "RabbitMQ connection string",
Hint = "RabbitMQ connection string [amqp://user:pass@host:10000/vhost] - https://www.rabbitmq.com/uri-spec.html",
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid },
Order = 2,
Category = PropertyCategories.Configuration)]
@ -78,7 +84,7 @@ namespace Elsa.Activities.RabbitMq
}
private async Task StartClient()
{
var config = new RabbitMqBusConfiguration(ConnectionString, RoutingKey, Headers);
var config = new RabbitMqBusConfiguration(ConnectionString, ExchangeName, RoutingKey, Headers);
var client = await _messageReceiverClientFactory.GetReceiverAsync(config);
client.StartClient();

View file

@ -10,7 +10,16 @@ namespace Elsa.Activities.RabbitMq
public static IActivityBuilder MessageReceived(this IBuilder builder, Action<ISetupActivity<RabbitMqMessageReceived>> setup, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.Then(setup, null, lineNumber, sourceFile);
public static IActivityBuilder MessageReceived(this IBuilder builder, string connectionString, string exchangeName, string routingKey, Dictionary<string, string> headers, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.MessageReceived(setup => setup.WithConnectionString(connectionString).WithExchangeName(exchangeName).WithRoutingKey(routingKey).WithHeaders(headers), lineNumber, sourceFile);
public static IActivityBuilder MessageReceived(this IBuilder builder, string connectionString, string routingKey, Dictionary<string, string> headers, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.MessageReceived(setup => setup.WithConnectionString(connectionString).WithRoutingKey(routingKey).WithHeaders(headers), lineNumber, sourceFile);
public static IActivityBuilder MessageReceived(this IBuilder builder, string connectionString, string exchangeName, string routingKey, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.MessageReceived(setup => setup.WithConnectionString(connectionString).WithExchangeName(exchangeName).WithRoutingKey(routingKey), lineNumber, sourceFile);
public static IActivityBuilder MessageReceived(this IBuilder builder, string connectionString, string routingKey, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.MessageReceived(setup => setup.WithConnectionString(connectionString).WithRoutingKey(routingKey), lineNumber, sourceFile);
}
}

View file

@ -14,6 +14,12 @@ namespace Elsa.Activities.RabbitMq
public static ISetupActivity<RabbitMqMessageReceived> WithConnectionString(this ISetupActivity<RabbitMqMessageReceived> messageReceived, Func<ActivityExecutionContext, string> value) => messageReceived.Set(x => x.ConnectionString, value!);
public static ISetupActivity<RabbitMqMessageReceived> WithConnectionString(this ISetupActivity<RabbitMqMessageReceived> messageReceived, string value) => messageReceived.Set(x => x.ConnectionString, value!);
public static ISetupActivity<RabbitMqMessageReceived> WithExchangeName(this ISetupActivity<RabbitMqMessageReceived> messageReceived, Func<ActivityExecutionContext, ValueTask<string>> value) => messageReceived.Set(x => x.ExchangeName, value!);
public static ISetupActivity<RabbitMqMessageReceived> WithExchangeName(this ISetupActivity<RabbitMqMessageReceived> messageReceived, Func<ValueTask<string>> value) => messageReceived.Set(x => x.ExchangeName, value!);
public static ISetupActivity<RabbitMqMessageReceived> WithExchangeName(this ISetupActivity<RabbitMqMessageReceived> messageReceived, Func<string> value) => messageReceived.Set(x => x.ExchangeName, value!);
public static ISetupActivity<RabbitMqMessageReceived> WithExchangeName(this ISetupActivity<RabbitMqMessageReceived> messageReceived, Func<ActivityExecutionContext, string> value) => messageReceived.Set(x => x.ExchangeName, value!);
public static ISetupActivity<RabbitMqMessageReceived> WithExchangeName(this ISetupActivity<RabbitMqMessageReceived> messageReceived, string value) => messageReceived.Set(x => x.ExchangeName, value!);
public static ISetupActivity<RabbitMqMessageReceived> WithRoutingKey(this ISetupActivity<RabbitMqMessageReceived> messageReceived, Func<ActivityExecutionContext, ValueTask<string>> value) => messageReceived.Set(x => x.RoutingKey, value!);
public static ISetupActivity<RabbitMqMessageReceived> WithRoutingKey(this ISetupActivity<RabbitMqMessageReceived> messageReceived, Func<ValueTask<string>> value) => messageReceived.Set(x => x.RoutingKey, value!);
public static ISetupActivity<RabbitMqMessageReceived> WithRoutingKey(this ISetupActivity<RabbitMqMessageReceived> messageReceived, Func<string> value) => messageReceived.Set(x => x.RoutingKey, value!);

View file

@ -27,14 +27,20 @@ namespace Elsa.Activities.RabbitMq
}
[ActivityInput(
Hint = "Topic",
Hint = "Exchange where message will be published",
Order = 1,
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
public string ExchangeName { get; set; } = default!;
[ActivityInput(
Hint = "Topic",
Order = 2,
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
public string RoutingKey { get; set; } = default!;
[ActivityInput(
Hint = "List of headers that should be present in the message",
Order = 2,
Order = 3,
UIHint = ActivityInputUIHints.Dictionary,
DefaultSyntax = SyntaxNames.Json,
SupportedSyntaxes = new[] { SyntaxNames.Json })]
@ -42,13 +48,13 @@ namespace Elsa.Activities.RabbitMq
[ActivityInput(
Hint = "Message body",
Order = 3,
Order = 4,
UIHint = ActivityInputUIHints.MultiLine,
SupportedSyntaxes = new[] { SyntaxNames.Json })]
public string Message { get; set; } = default!;
[ActivityInput(
Hint = "RabbitMQ connection string",
Hint = "RabbitMQ connection string [amqp://user:pass@host:10000/vhost] - https://www.rabbitmq.com/uri-spec.html",
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid },
Order = 1,
Category = PropertyCategories.Configuration)]
@ -56,7 +62,7 @@ namespace Elsa.Activities.RabbitMq
protected override async ValueTask<IActivityExecutionResult> OnExecuteAsync(ActivityExecutionContext context)
{
var config = new RabbitMqBusConfiguration(ConnectionString, RoutingKey, Headers);
var config = new RabbitMqBusConfiguration(ConnectionString, ExchangeName, RoutingKey, Headers);
var client = await _messageSenderClientFactory.GetSenderAsync(config);

View file

@ -12,6 +12,18 @@ namespace Elsa.Activities.RabbitMq
public static IActivityBuilder SendTopicMessage(this IBuilder builder, Action<ISetupActivity<SendRabbitMqMessage>> setup, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.Then(setup, null, lineNumber, sourceFile);
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string exchangeName, string topic, Dictionary<string, string> headers, Func<ActivityExecutionContext, ValueTask<string>> message, [CallerLineNumber] int lineNumber = default,
[CallerFilePath] string? sourceFile = default) => builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithExchangeName(exchangeName).WithTopic(topic).WithHeaders(headers).WithMessage(message), lineNumber, sourceFile);
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string exchangeName, string topic, Dictionary<string, string> headers, Func<ActivityExecutionContext, string> message, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithExchangeName(exchangeName).WithTopic(topic).WithHeaders(headers).WithMessage(message), lineNumber, sourceFile);
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string exchangeName, string topic, Dictionary<string, string> headers, Func<string> message, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithExchangeName(exchangeName).WithTopic(topic).WithHeaders(headers).WithMessage(message), lineNumber, sourceFile);
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string exchangeName, string topic, Dictionary<string, string> headers, string message, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithExchangeName(exchangeName).WithTopic(topic).WithHeaders(headers).WithMessage(message), lineNumber, sourceFile);
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string topic, Dictionary<string, string> headers, Func<ActivityExecutionContext, ValueTask<string>> message, [CallerLineNumber] int lineNumber = default,
[CallerFilePath] string? sourceFile = default) => builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithTopic(topic).WithHeaders(headers).WithMessage(message), lineNumber, sourceFile);
@ -23,5 +35,31 @@ namespace Elsa.Activities.RabbitMq
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string topic, Dictionary<string, string> headers, string message, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithTopic(topic).WithHeaders(headers).WithMessage(message), lineNumber, sourceFile);
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string exchangeName, string topic, Func<ActivityExecutionContext, ValueTask<string>> message, [CallerLineNumber] int lineNumber = default,
[CallerFilePath] string? sourceFile = default) => builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithExchangeName(exchangeName).WithTopic(topic).WithMessage(message), lineNumber, sourceFile);
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string exchangeName, string topic, Func<ActivityExecutionContext, string> message, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithExchangeName(exchangeName).WithTopic(topic).WithMessage(message), lineNumber, sourceFile);
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string exchangeName, string topic, Func<string> message, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithExchangeName(exchangeName).WithTopic(topic).WithMessage(message), lineNumber, sourceFile);
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string exchangeName, string topic, string message, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithExchangeName(exchangeName).WithTopic(topic).WithMessage(message), lineNumber, sourceFile);
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string topic, Func<ActivityExecutionContext, ValueTask<string>> message, [CallerLineNumber] int lineNumber = default,
[CallerFilePath] string? sourceFile = default) => builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithTopic(topic).WithMessage(message), lineNumber, sourceFile);
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string topic, Func<ActivityExecutionContext, string> message, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithTopic(topic).WithMessage(message), lineNumber, sourceFile);
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string topic, Func<string> message, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithTopic(topic).WithMessage(message), lineNumber, sourceFile);
public static IActivityBuilder SendTopicMessage(this IBuilder builder, string connectionString, string topic, string message, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) =>
builder.SendTopicMessage(setup => setup.WithConnectionString(connectionString).WithTopic(topic).WithMessage(message), lineNumber, sourceFile);
}
}

View file

@ -14,6 +14,12 @@ namespace Elsa.Activities.RabbitMq
public static ISetupActivity<SendRabbitMqMessage> WithConnectionString(this ISetupActivity<SendRabbitMqMessage> sendMessage, Func<ActivityExecutionContext, string> value) => sendMessage.Set(x => x.ConnectionString, value!);
public static ISetupActivity<SendRabbitMqMessage> WithConnectionString(this ISetupActivity<SendRabbitMqMessage> sendMessage, string value) => sendMessage.Set(x => x.ConnectionString, value!);
public static ISetupActivity<SendRabbitMqMessage> WithExchangeName(this ISetupActivity<SendRabbitMqMessage> sendMessage, Func<ActivityExecutionContext, ValueTask<string>> value) => sendMessage.Set(x => x.ExchangeName, value!);
public static ISetupActivity<SendRabbitMqMessage> WithExchangeName(this ISetupActivity<SendRabbitMqMessage> sendMessage, Func<ValueTask<string>> value) => sendMessage.Set(x => x.ExchangeName, value!);
public static ISetupActivity<SendRabbitMqMessage> WithExchangeName(this ISetupActivity<SendRabbitMqMessage> sendMessage, Func<string> value) => sendMessage.Set(x => x.ExchangeName, value!);
public static ISetupActivity<SendRabbitMqMessage> WithExchangeName(this ISetupActivity<SendRabbitMqMessage> sendMessage, Func<ActivityExecutionContext, string> value) => sendMessage.Set(x => x.ExchangeName, value!);
public static ISetupActivity<SendRabbitMqMessage> WithExchangeName(this ISetupActivity<SendRabbitMqMessage> sendMessage, string value) => sendMessage.Set(x => x.ExchangeName, value!);
public static ISetupActivity<SendRabbitMqMessage> WithTopic(this ISetupActivity<SendRabbitMqMessage> sendMessage, Func<ActivityExecutionContext, ValueTask<string>> value) => sendMessage.Set(x => x.RoutingKey, value!);
public static ISetupActivity<SendRabbitMqMessage> WithTopic(this ISetupActivity<SendRabbitMqMessage> sendMessage, Func<ValueTask<string>> value) => sendMessage.Set(x => x.RoutingKey, value!);
public static ISetupActivity<SendRabbitMqMessage> WithTopic(this ISetupActivity<SendRabbitMqMessage> sendMessage, Func<string> value) => sendMessage.Set(x => x.RoutingKey, value!);

View file

@ -11,14 +11,16 @@ namespace Elsa.Activities.RabbitMq.Bookmarks
{
}
public MessageReceivedBookmark(string routingKey, string connectionString, Dictionary<string, string> headers)
public MessageReceivedBookmark(string exchangeName, string routingKey, string connectionString, Dictionary<string, string> headers)
{
ExchangeName = exchangeName;
RoutingKey = routingKey;
ConnectionString = connectionString;
Headers = headers ?? new Dictionary<string, string>();
}
public string ExchangeName { get; set; } = default!;
public string RoutingKey { get; set; } = default!;
public string ConnectionString { get; set; } = default!;
public Dictionary<string, string> Headers { get; set; } = default!;
@ -31,6 +33,7 @@ namespace Elsa.Activities.RabbitMq.Bookmarks
{
Result(new MessageReceivedBookmark
{
ExchangeName = (await context.ReadActivityPropertyAsync(x => x.ExchangeName, cancellationToken))!,
RoutingKey = (await context.ReadActivityPropertyAsync(x => x.RoutingKey, cancellationToken))!,
ConnectionString = (await context.ReadActivityPropertyAsync(x => x.ConnectionString, cancellationToken))!,
Headers = (await context.ReadActivityPropertyAsync(x => x.Headers, cancellationToken))!

View file

@ -6,12 +6,14 @@ namespace Elsa.Activities.RabbitMq.Configuration
public class RabbitMqBusConfiguration
{
public string ConnectionString { get; }
public string ExchangeName { get; }
public string RoutingKey { get; }
public Dictionary<string, string> Headers { get; }
public RabbitMqBusConfiguration(string connectionString, string routingKey, Dictionary<string, string> headers)
public RabbitMqBusConfiguration(string connectionString, string exchangeName, string routingKey, Dictionary<string, string> headers)
{
ConnectionString = connectionString;
ExchangeName = exchangeName;
RoutingKey = routingKey;
Headers = headers ?? new Dictionary<string, string>();
}
@ -20,7 +22,9 @@ namespace Elsa.Activities.RabbitMq.Configuration
{
var headersString = string.Concat(Headers.Select((x, y) => string.Concat(x, y)));
return System.HashCode.Combine(ConnectionString, RoutingKey, headersString);
return System.HashCode.Combine(ConnectionString, ExchangeName, RoutingKey, headersString);
}
public string TopicFullName => string.IsNullOrEmpty(ExchangeName) ? RoutingKey : $"{RoutingKey}@{ExchangeName}";
}
}

View file

@ -42,18 +42,18 @@ namespace Elsa.Activities.RabbitMq.Services
}))
.Transport(t =>
{
t.UseRabbitMq(Configuration.ConnectionString, $"Elsa{Guid.NewGuid().ToString("n").ToUpper()}").InputQueueOptions(o => o.SetAutoDelete(autoDelete: true));
t.UseRabbitMq(Configuration.ConnectionString, $"Elsa{Guid.NewGuid().ToString("n").ToUpper()}");
})
.Start();
_bus.Advanced.Topics.Subscribe(Configuration.RoutingKey);
_bus.Advanced.Topics.Subscribe(Configuration.TopicFullName);
}
public async Task PublishMessage(string message)
{
if (_bus == null) ConfigureAsOneWayClient();
await _bus!.Advanced.Topics.Publish(Configuration.RoutingKey, message, Configuration.Headers);
await _bus!.Advanced.Topics.Publish(Configuration.TopicFullName, message, Configuration.Headers);
}
public void Dispose()

View file

@ -95,9 +95,10 @@ namespace Elsa.Activities.RabbitMq.Services
{
var connectionString = await activity.EvaluatePropertyValueAsync(x => x.ConnectionString, cancellationToken);
var routingKey = await activity.EvaluatePropertyValueAsync(x => x.RoutingKey, cancellationToken);
var exchangeName = await activity.EvaluatePropertyValueAsync(x => x.ExchangeName, cancellationToken);
var headers = await activity.EvaluatePropertyValueAsync(x => x.Headers, cancellationToken);
var config = new RabbitMqBusConfiguration(connectionString!, routingKey!, headers!);
var config = new RabbitMqBusConfiguration(connectionString!, exchangeName, routingKey!, headers!);
yield return config!;
}

View file

@ -51,7 +51,7 @@ namespace Elsa.Activities.RabbitMq.Services
var config = _client.Configuration;
var bookmark = new MessageReceivedBookmark(config.RoutingKey, config.ConnectionString, config.Headers);
var bookmark = new MessageReceivedBookmark(config.ExchangeName, config.RoutingKey, config.ConnectionString, config.Headers);
var launchContext = new WorkflowsQuery(ActivityType, bookmark);
await _workflowLaunchpad.UseServiceAsync(service => service.CollectAndDispatchWorkflowsAsync(launchContext, new WorkflowInput(message), cancellationToken));

View file

@ -19,7 +19,7 @@ namespace Elsa.Samples.RabbitMqWorker.Workflows
{
builder
.Timer(Duration.FromSeconds(5))
.MessageReceived(_connectionString, "Podcasts.Weather", default!)
.MessageReceived(_connectionString, "Podcasts.Weather")
.WriteLine(context =>
{
var message = context.GetInput<string>();

View file

@ -20,7 +20,7 @@ namespace Elsa.Samples.RabbitMqWorker.Workflows
builder
.Timer(Duration.FromSeconds(5))
.WriteLine("Sending a weather update with the \"Podcasts.Weather\" topic.")
.SendTopicMessage(_connectionString, "Podcasts.Weather", default!, "Cloudy with a chance of meatballs");
.SendTopicMessage(_connectionString, "Podcasts.Weather", "Cloudy with a chance of meatballs");
}
}
}

View file

@ -22,8 +22,8 @@ namespace Elsa.Samples.RabbitMqWorker.Workflows
return $"Start! - correlationId: {correlationId}";
})
.SendTopicMessage(_connectionString, "Greetings", default!, "Greetings from RabbitMQ")
.MessageReceived(_connectionString, "Greetings", default!)
.SendTopicMessage(_connectionString, "Greetings", "Greetings from RabbitMQ")
.MessageReceived(_connectionString, "Greetings")
.WriteLine(ctx => "End: " + (string?)ctx.Input);
}