![]() |
VOOZH | about |
dotnet add package Excalibur.Outbox.DynamoDb --version 3.0.0-alpha.208
NuGet\Install-Package Excalibur.Outbox.DynamoDb -Version 3.0.0-alpha.208
<PackageReference Include="Excalibur.Outbox.DynamoDb" Version="3.0.0-alpha.208" />
<PackageVersion Include="Excalibur.Outbox.DynamoDb" Version="3.0.0-alpha.208" />Directory.Packages.props
<PackageReference Include="Excalibur.Outbox.DynamoDb" />Project file
paket add Excalibur.Outbox.DynamoDb --version 3.0.0-alpha.208
#r "nuget: Excalibur.Outbox.DynamoDb, 3.0.0-alpha.208"
#:package Excalibur.Outbox.DynamoDb@3.0.0-alpha.208
#addin nuget:?package=Excalibur.Outbox.DynamoDb&version=3.0.0-alpha.208&prereleaseInstall as a Cake Addin
#tool nuget:?package=Excalibur.Outbox.DynamoDb&version=3.0.0-alpha.208&prereleaseInstall as a Cake Tool
AWS DynamoDB implementation of the cloud-native outbox pattern for reliable message delivery.
dotnet add package Excalibur.Outbox.DynamoDb
services.AddDynamoDbOutboxStore(options =>
{
options.Connection.Region = "us-east-1";
options.TableName = "outbox";
options.DefaultTimeToLiveSeconds = 604800; // 7 days
options.CreateTableIfNotExists = true;
options.EnableStreams = true;
});
Or via configuration:
services.AddDynamoDbOutboxStore(configuration.GetSection("DynamoDbOutbox"));
services.AddDynamoDbOutboxStore(options =>
{
options.Connection.ServiceUrl = "http://localhost:8000";
options.TableName = "outbox";
options.Connection.AccessKey = "local";
options.Connection.SecretKey = "local";
});
public class MyService
{
private readonly ICloudNativeOutboxStore _outbox;
public MyService(ICloudNativeOutboxStore outbox)
{
_outbox = outbox;
}
public async Task PublishEventAsync(OrderPlaced @event, CancellationToken ct)
{
var message = new CloudOutboxMessage
{
MessageId = Guid.NewGuid().ToString(),
MessageType = nameof(OrderPlaced),
Payload = JsonSerializer.SerializeToUtf8Bytes(@event),
AggregateId = @event.OrderId,
AggregateType = "Order",
PartitionKeyValue = @event.OrderId,
CreatedAt = DateTimeOffset.UtcNow
};
var partitionKey = new PartitionKey(@event.OrderId);
var result = await _outbox.AddAsync(message, partitionKey, ct);
if (!result.Success)
{
// Handle failure
}
}
}
// Subscribe to new outbox messages
var subscription = await _outbox.SubscribeToNewMessagesAsync(
new ChangeFeedOptions { StartPosition = ChangeFeedStartPosition.Now },
ct);
await foreach (var change in subscription.ReadChangesAsync(ct))
{
if (change.Document != null)
{
// Publish to message broker
await _messageBroker.PublishAsync(change.Document);
// Mark as published
await _outbox.MarkAsPublishedAsync(
change.DocumentId,
change.PartitionKey,
ct);
}
}
For serverless scenarios, use DynamoDB Streams trigger:
public class OutboxProcessor
{
private readonly IMessageBroker _messageBroker;
private readonly ICloudNativeOutboxStore _outbox;
public async Task ProcessStreamRecordsAsync(
DynamoDBEvent dynamoEvent,
CancellationToken ct)
{
foreach (var record in dynamoEvent.Records)
{
if (record.EventName != "INSERT")
continue;
var newImage = record.Dynamodb.NewImage;
// Check if unpublished
if (newImage.TryGetValue("isPublished", out var isPublished)
&& isPublished.BOOL)
continue;
var messageId = newImage["sk"].S;
var partitionKey = newImage["pk"].S;
var payload = Convert.FromBase64String(newImage["payload"].S);
// Publish to message broker
await _messageBroker.PublishAsync(payload);
// Mark as published
await _outbox.MarkAsPublishedAsync(
messageId,
new PartitionKey(partitionKey),
ct);
}
}
}
The outbox uses the following DynamoDB table schema:
| Attribute | Type | Description |
|---|---|---|
| pk | String (HASH) | Partition key value |
| sk | String (RANGE) | Message ID (sort key) |
| messageType | String | Message type name |
| payload | String | Base64-encoded message payload |
| headers | String | JSON-encoded headers |
| aggregateId | String | Associated aggregate ID |
| aggregateType | String | Associated aggregate type |
| correlationId | String | Correlation ID for tracing |
| causationId | String | Causation ID linking to causing message |
| createdAt | String | ISO 8601 timestamp |
| publishedAt | String | ISO 8601 timestamp when published |
| isPublished | Boolean | Publication status |
| retryCount | Number | Number of retry attempts |
| lastError | String | Last error message |
| ttl | Number | Unix timestamp for TTL expiration |
The table is created with streams enabled:
NEW_AND_OLD_IMAGESttl attributeExcalibur.Data.Abstractions for cloud-native interfacesExcalibur.Data.DynamoDb for DynamoDB SDK setupSee LICENSE files in repository root.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.0-alpha.208 | 42 | 6/11/2026 |
| 3.0.0-alpha.207 | 46 | 6/11/2026 |
| 3.0.0-alpha.205 | 48 | 6/10/2026 |
| 3.0.0-alpha.204 | 50 | 6/8/2026 |
| 3.0.0-alpha.203 | 53 | 6/8/2026 |
| 3.0.0-alpha.202 | 46 | 6/8/2026 |
| 3.0.0-alpha.201 | 48 | 6/8/2026 |
| 3.0.0-alpha.199 | 49 | 6/8/2026 |
| 3.0.0-alpha.198 | 45 | 5/28/2026 |
| 3.0.0-alpha.197 | 64 | 5/28/2026 |
| 3.0.0-alpha.194 | 56 | 5/20/2026 |
| 3.0.0-alpha.193 | 55 | 5/13/2026 |
| 3.0.0-alpha.192 | 46 | 5/13/2026 |
| 3.0.0-alpha.191 | 48 | 5/13/2026 |
| 3.0.0-alpha.189 | 47 | 5/12/2026 |
| 3.0.0-alpha.187 | 54 | 5/8/2026 |
| 3.0.0-alpha.185 | 52 | 5/7/2026 |
| 3.0.0-alpha.183 | 46 | 5/7/2026 |
| 3.0.0-alpha.182 | 45 | 5/6/2026 |
| 3.0.0-alpha.181 | 48 | 5/6/2026 |