Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion playground/TestShop/AppHost/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
.WithReference(catalogDb)
.WithReplicas(2);

var messaging = builder.AddRabbitMQ("messaging").PublishAsContainer();
var rabbitMqPassword = builder.AddParameter("rabbitmq-password", secret: true);
var messaging = builder.AddRabbitMQ("messaging", password: rabbitMqPassword)
.WithDataVolume()
.PublishAsContainer();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is .PublishAsContainer(); necessary?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't add that, it was there already.


var basketService = builder.AddProject("basketservice", @"..\BasketService\BasketService.csproj")
.WithReference(basketCache)
Expand Down
7 changes: 5 additions & 2 deletions playground/TestShop/BasketService/BasketService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,14 @@ public override async Task<CheckoutCustomerBasketResponse> CheckoutBasket(Checko
}

using var channel = _messageConnection.CreateModel();
channel.QueueDeclare(queueName, exclusive: false);
channel.QueueDeclare(queueName, durable: true, exclusive: false);

var props = channel.CreateBasicProperties();
props.Persistent = true; // or props.DeliveryMode = 2;
channel.BasicPublish(
exchange: "",
routingKey: queueName,
basicProperties: null,
basicProperties: props,
body: JsonSerializer.SerializeToUtf8Bytes(order));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ protected override Task ExecuteAsync(CancellationToken stoppingToken)
_messageConnection = _serviceProvider.GetRequiredService<IConnection>();

_messageChannel = _messageConnection.CreateModel();
_messageChannel.QueueDeclare(queueName, exclusive: false);
_messageChannel.QueueDeclare(queueName, durable: true, exclusive: false);

var consumer = new EventingBasicConsumer(_messageChannel);
consumer.Received += ProcessMessageAsync;
Expand Down
22 changes: 20 additions & 2 deletions src/Aspire.Hosting.RabbitMQ/RabbitMQBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ public static IResourceBuilder<RabbitMQServerResource> AddRabbitMQ(this IDistrib
/// <param name="isReadOnly">A flag that indicates if this is a read-only volume.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<RabbitMQServerResource> WithDataVolume(this IResourceBuilder<RabbitMQServerResource> builder, string? name = null, bool isReadOnly = false)
=> builder.WithVolume(name ?? VolumeNameGenerator.CreateVolumeName(builder, "data"), "/var/lib/rabbitmq", isReadOnly);
=> builder
.WithVolume(name ?? VolumeNameGenerator.CreateVolumeName(builder, "data"), "/var/lib/rabbitmq", isReadOnly)
.RunWithStableNodeName();

/// <summary>
/// Adds a bind mount for the data folder to a RabbitMQ container resource.
Expand All @@ -58,5 +60,21 @@ public static IResourceBuilder<RabbitMQServerResource> WithDataVolume(this IReso
/// <param name="isReadOnly">A flag that indicates if this is a read-only mount.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<RabbitMQServerResource> WithDataBindMount(this IResourceBuilder<RabbitMQServerResource> builder, string source, bool isReadOnly = false)
=> builder.WithBindMount(source, "/var/lib/rabbitmq", isReadOnly);
=> builder.WithBindMount(source, "/var/lib/rabbitmq", isReadOnly)
.RunWithStableNodeName();

private static IResourceBuilder<RabbitMQServerResource> RunWithStableNodeName(this IResourceBuilder<RabbitMQServerResource> builder)
{
if (builder.ApplicationBuilder.ExecutionContext.IsRunMode)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when you publish?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assumption is when you publish the host name of the container is stable, rather than what happens in dev where we randomize the port every time.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More details about how RabbitMQ auto-assigns node names in their docs: https://www.rabbitmq.com/docs/clustering#node-names and https://www.rabbitmq.com/docs/configure

From the latter link:

The node name should be unique per Erlang-node-and-machine combination. To run multiple nodes, see the clustering guide.

Default:
Unix: rabbit@$HOSTNAME
Windows: rabbit@%COMPUTERNAME%

So ultimately, what happens after publish depends on what $HOSTNAME results in on the container where RabbitMQ is running.

{
builder.WithEnvironment(context =>
{
// Set a stable node name so queue storage is consistent between sessions
var nodeName = $"{builder.Resource.Name}@localhost";
context.EnvironmentVariables["RABBITMQ_NODENAME"] = nodeName;
});
}

return builder;
}
}