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
12 changes: 12 additions & 0 deletions docs/guide/messaging/transports/azureservicebus/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,20 @@ builder.UseWolverine(opts =>
<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Transports/Azure/Wolverine.AzureServiceBus.Tests/end_to_end_with_named_broker.cs#L26-L44' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_named_azure_service_bus_broker' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## URI reference

The `AzureServiceBusEndpointUri` helper class builds canonical endpoint URIs:

| URI form | Helper call |
|---|---|
| `asb://queue/{name}` | `AzureServiceBusEndpointUri.Queue("name")` |
| `asb://topic/{name}` | `AzureServiceBusEndpointUri.Topic("name")` |
| `asb://topic/{topic}/{subscription}` | `AzureServiceBusEndpointUri.Subscription("topic", "sub")` |

```csharp
using Wolverine.AzureServiceBus;

var uri = AzureServiceBusEndpointUri.Subscription("events", "audit");
```


14 changes: 14 additions & 0 deletions docs/guide/messaging/transports/gcp-pubsub/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,17 @@ opts.UsePubsub("your-project-id")
```

The default delimiter between the prefix and the original name is `.` for GCP Pub/Sub (e.g., `dev-john.orders`).

## URI reference

The `GcpPubsubEndpointUri` helper class builds canonical endpoint URIs:

| URI form | Helper call |
|---|---|
| `pubsub://{projectId}/{topicName}` | `GcpPubsubEndpointUri.Topic("projectId", "topicName")` |

```csharp
using Wolverine.Pubsub;

var uri = GcpPubsubEndpointUri.Topic("my-project", "orders");
```
14 changes: 14 additions & 0 deletions docs/guide/messaging/transports/kafka.md
Original file line number Diff line number Diff line change
Expand Up @@ -678,3 +678,17 @@ await bus.BroadcastToTopicAsync("my-topic", new KafkaTombstone("record-key-to-de
When Wolverine encounters a `KafkaTombstone` message, it produces a Kafka message with the specified key and a `null` value. This signals to Kafka's log compaction process that the record with that key should be removed during the next compaction cycle.

This is useful when your Kafka topics use [log compaction](https://docs.confluent.io/platform/current/kafka/design.html#log-compaction) to maintain a key-value snapshot of the latest state. Publishing a tombstone ensures that deleted records are eventually cleaned up from the topic.

## URI reference

The `KafkaEndpointUri` helper class builds canonical endpoint URIs:

| URI form | Helper call |
|---|---|
| `kafka://topic/{name}` | `KafkaEndpointUri.Topic("name")` |

```csharp
using Wolverine.Kafka;

var uri = KafkaEndpointUri.Topic("orders");
```
13 changes: 13 additions & 0 deletions docs/guide/messaging/transports/mqtt.md
Original file line number Diff line number Diff line change
Expand Up @@ -466,3 +466,16 @@ await host.StartAsync();
<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Transports/MQTT/Wolverine.MQTT.Tests/Samples.cs#L128-L159' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_applying_custom_mqtt_envelope_mapper' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## URI reference

The `MqttEndpointUri` helper class builds canonical endpoint URIs:

| URI form | Helper call |
|---|---|
| `mqtt://topic/{name}` | `MqttEndpointUri.Topic("name")` |

```csharp
using Wolverine.MQTT;

var uri = MqttEndpointUri.Topic("sensor/temperature");
```
14 changes: 14 additions & 0 deletions docs/guide/messaging/transports/nats.md
Original file line number Diff line number Diff line change
Expand Up @@ -423,3 +423,17 @@ docker run -d --name nats -p 4222:4222 -p 8222:8222 nats:latest --jetstream -m 8
# For scheduled delivery tests, use NATS 2.12+
docker run -d --name nats -p 4222:4222 -p 8222:8222 nats:2.12-alpine --jetstream -m 8222
```

## URI reference

The `NatsEndpointUri` helper class builds canonical endpoint URIs:

| URI form | Helper call |
|---|---|
| `nats://subject/{subject}` | `NatsEndpointUri.Subject("subject")` |

```csharp
using Wolverine.Nats;

var uri = NatsEndpointUri.Subject("orders.created");
```
21 changes: 21 additions & 0 deletions docs/guide/messaging/transports/pulsar.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,24 @@ Also see the more generic [Wolverine Guide on Interoperability](/tutorials/inter
:::

Pulsar interoperability is done through the `IPulsarEnvelopeMapper` interface.

## URI reference

The `PulsarEndpointUri` helper class produces Wolverine endpoint URIs of the form `pulsar://persistent/{tenant}/{ns}/{topic}` or `pulsar://non-persistent/{tenant}/{ns}/{topic}` — the form Wolverine's parser accepts. Pulsar-native topic-path strings (`persistent://...`) used by the native Pulsar client are a separate concept and are not built by this helper.

| Helper call | Resulting URI |
|---|---|
| `PulsarEndpointUri.PersistentTopic("public", "default", "orders")` | `pulsar://persistent/public/default/orders` |
| `PulsarEndpointUri.NonPersistentTopic("public", "default", "orders")` | `pulsar://non-persistent/public/default/orders` |
| `PulsarEndpointUri.Topic("public", "default", "orders", persistent: true)` | `pulsar://persistent/public/default/orders` |
| `PulsarEndpointUri.Topic("persistent://public/default/orders")` | `pulsar://persistent/public/default/orders` |

```csharp
using Wolverine.Pulsar;

var uri = PulsarEndpointUri.PersistentTopic("public", "default", "orders");
```

::: tip
`PulsarEndpoint.UriFor` is deprecated. Use `PulsarEndpointUri.Topic` (string overload) or `PersistentTopic`/`NonPersistentTopic` instead. The old `UriFor(bool, ...)` overload returned a Pulsar-native topic path, not a Wolverine endpoint URI — if you need that format, build the string directly.
:::
18 changes: 18 additions & 0 deletions docs/guide/messaging/transports/rabbitmq/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,21 @@ This creates RabbitMQ queues named `sequenced1` through `sequenced5` with compan
::: info
Wolverine with the `WolverineFX.RabbitMQ` transport has also been verified to work against [LavinMQ](https://lavinmq.com/), a modern RabbitMQ-protocol compatible message broker, using the RabbitMQ transport with 100% protocol compatibility when configured through the standard RabbitMQ integration shown above.
:::

## URI reference

The `RabbitMqEndpointUri` helper class builds canonical endpoint URIs:

| URI form | Helper call |
|---|---|
| `rabbitmq://queue/{name}` | `RabbitMqEndpointUri.Queue("name")` |
| `rabbitmq://exchange/{name}` | `RabbitMqEndpointUri.Exchange("name")` |
| `rabbitmq://topic/{exchange}/{routingKey}` | `RabbitMqEndpointUri.Topic("ex", "key")` |
| `rabbitmq://exchange/{exchange}/routing/{routingKey}` | `RabbitMqEndpointUri.Routing("ex", "key")` |

```csharp
using Wolverine.RabbitMQ;

var uri = RabbitMqEndpointUri.Queue("orders");
// new Uri("rabbitmq://queue/orders")
```
17 changes: 17 additions & 0 deletions docs/guide/messaging/transports/redis.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,4 +259,21 @@ using var host = await builder.UseWolverine(opts =>
<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Transports/Redis/Wolverine.Redis.Tests/Samples/RedisTransportWithScheduling.cs#L7-L36' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_dead_letter_queue_for_redis' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## URI reference

The `RedisEndpointUri` helper class builds canonical endpoint URIs:

| URI form | Helper call |
|---|---|
| `redis://stream/{databaseId}/{streamKey}` | `RedisEndpointUri.Stream("key", databaseId: 0)` |
| `redis://stream/{databaseId}/{streamKey}?consumerGroup={group}` | `RedisEndpointUri.Stream("key", 0, "group")` |

```csharp
using Wolverine.Redis;

var uri = RedisEndpointUri.Stream("orders", databaseId: 3);
```

::: tip
`RedisTransport.BuildRedisStreamUri` is deprecated. Use `RedisEndpointUri.Stream` instead.
:::
16 changes: 16 additions & 0 deletions docs/guide/messaging/transports/sns.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,19 @@ Also see the more generic [Wolverine Guide on Interoperability](/tutorials/inter

SNS interoperability is done through the `ISnsEnvelopeMapper`. At this point, SNS supports interoperability through
MassTransit, NServiceBus, CloudEvents, or user defined mapping strategies.

## URI reference

The `SnsEndpointUri` helper class builds canonical endpoint URIs:

| URI form | Helper call |
|---|---|
| `sns://{name}` | `SnsEndpointUri.Topic("name")` |

```csharp
using Wolverine.AmazonSns;

var uri = SnsEndpointUri.Topic("events");
// FIFO topic (suffix preserved verbatim):
var fifoUri = SnsEndpointUri.Topic("events.fifo");
```
16 changes: 16 additions & 0 deletions docs/guide/messaging/transports/sqs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,19 @@ using var host = await Host.CreateDefaultBuilder()
opts.PublishAllMessages().ToSqsQueue("send-and-receive");
}).StartAsync();
```

## URI reference

The `SqsEndpointUri` helper class builds canonical endpoint URIs:

| URI form | Helper call |
|---|---|
| `sqs://{name}` | `SqsEndpointUri.Queue("name")` |

```csharp
using Wolverine.AmazonSqs;

var uri = SqsEndpointUri.Queue("orders");
// FIFO queue (suffix preserved verbatim):
var fifoUri = SqsEndpointUri.Queue("orders.fifo");
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Shouldly;
using Xunit;

namespace Wolverine.AmazonSns.Tests;

public class SnsEndpointUriTests
{
[Fact]
public void topic_uri_has_expected_shape()
{
SnsEndpointUri.Topic("events")
.ShouldBe(new Uri("sns://events"));
}

[Fact]
public void topic_uri_preserves_fifo_suffix()
{
SnsEndpointUri.Topic("events.fifo")
.ShouldBe(new Uri("sns://events.fifo"));
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public void topic_rejects_invalid_name(string? name)
{
Should.Throw<ArgumentException>(() => SnsEndpointUri.Topic(name!));
}

[Fact]
public void topic_uri_roundtrips_through_parser()
{
var uri = SnsEndpointUri.Topic("events");
var transport = new Wolverine.AmazonSns.Internal.AmazonSnsTransport();
var endpoint = transport.GetOrCreateEndpoint(uri);
endpoint.Uri.ShouldBe(uri);
}
}
21 changes: 21 additions & 0 deletions src/Transports/AWS/Wolverine.AmazonSns/SnsEndpointUri.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace Wolverine.AmazonSns;

/// <summary>
/// Builds canonical Wolverine endpoint <see cref="Uri"/> values for AWS SNS transport endpoints.
/// </summary>
public static class SnsEndpointUri
{
/// <summary>
/// Builds a URI referencing an SNS topic endpoint in the canonical form
/// <c>sns://{topicName}</c>. FIFO topic names (with <c>.fifo</c> suffix) are preserved verbatim.
/// </summary>
/// <param name="topicName">The SNS topic name.</param>
/// <returns>A <see cref="Uri"/> of the form <c>sns://{topicName}</c>.</returns>
/// <example><c>SnsEndpointUri.Topic("events")</c> returns <c>sns://events</c>.</example>
/// <exception cref="ArgumentException">Thrown when <paramref name="topicName"/> is null, empty, or whitespace.</exception>
public static Uri Topic(string topicName)
{
ArgumentException.ThrowIfNullOrWhiteSpace(topicName);
return new Uri($"sns://{topicName}");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Shouldly;
using Xunit;

namespace Wolverine.AmazonSqs.Tests;

public class SqsEndpointUriTests
{
[Fact]
public void queue_uri_has_expected_shape()
{
SqsEndpointUri.Queue("orders")
.ShouldBe(new Uri("sqs://orders"));
}

[Fact]
public void queue_uri_preserves_fifo_suffix()
{
SqsEndpointUri.Queue("orders.fifo")
.ShouldBe(new Uri("sqs://orders.fifo"));
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public void queue_rejects_invalid_name(string? name)
{
Should.Throw<ArgumentException>(() => SqsEndpointUri.Queue(name!));
}

[Fact]
public void queue_uri_roundtrips_through_parser()
{
var uri = SqsEndpointUri.Queue("orders");
var transport = new Wolverine.AmazonSqs.Internal.AmazonSqsTransport();
var endpoint = transport.GetOrCreateEndpoint(uri);
endpoint.Uri.ShouldBe(uri);
}
}
21 changes: 21 additions & 0 deletions src/Transports/AWS/Wolverine.AmazonSqs/SqsEndpointUri.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace Wolverine.AmazonSqs;

/// <summary>
/// Builds canonical Wolverine endpoint <see cref="Uri"/> values for AWS SQS transport endpoints.
/// </summary>
public static class SqsEndpointUri
{
/// <summary>
/// Builds a URI referencing an SQS queue endpoint in the canonical form
/// <c>sqs://{queueName}</c>. FIFO queue names (with <c>.fifo</c> suffix) are preserved verbatim.
/// </summary>
/// <param name="queueName">The SQS queue name.</param>
/// <returns>A <see cref="Uri"/> of the form <c>sqs://{queueName}</c>.</returns>
/// <example><c>SqsEndpointUri.Queue("orders")</c> returns <c>sqs://orders</c>.</example>
/// <exception cref="ArgumentException">Thrown when <paramref name="queueName"/> is null, empty, or whitespace.</exception>
public static Uri Queue(string queueName)
{
ArgumentException.ThrowIfNullOrWhiteSpace(queueName);
return new Uri($"sqs://{queueName}");
}
}
Loading
Loading