Skip to content

Foundatio.AWS ​

Foundatio provides AWS implementations for file storage, queuing, and messaging using Amazon S3, Amazon SQS, and Amazon SNS. View source on GitHub →

Overview ​

ImplementationInterfacePackage
S3FileStorageIFileStorageFoundatio.AWS
SQSMessageBusIMessageBusFoundatio.AWS
SQSQueue<T>IQueue<T>Foundatio.AWS

Installation ​

bash
dotnet add package Foundatio.AWS

S3FileStorage ​

Store files in Amazon S3 with full support for buckets, prefixes, and metadata.

csharp
using Foundatio.Storage;

var storage = new S3FileStorage(o =>
{
    o.ConnectionString = connectionString;
    // Or: o.Bucket = "my-files"; o.Region = RegionEndpoint.USEast1;
});

await storage.SaveFileAsync("documents/report.pdf", pdfStream);

Configuration ​

OptionTypeRequiredDescription
Bucketstring✅S3 bucket name
RegionRegionEndpoint✅AWS region
ConnectionStringstringParses all settings
CredentialsAWSCredentialsAWS credentials
ServiceUrlstringCustom endpoint (e.g. Floci)

For additional options, see S3FileStorageOptions source.

SQSMessageBus ​

AWS SNS/SQS message bus for pub/sub messaging using the SNS fan-out pattern.

csharp
using Foundatio.Messaging;

var messageBus = new SQSMessageBus(o =>
{
    o.ConnectionString = connectionString;
    o.Topic = "events";
    // Optional: Specify queue name for durable subscriptions
    // o.SubscriptionQueueName = "my-service-queue";
});

await messageBus.SubscribeAsync<OrderCreated>(async order =>
{
    Console.WriteLine($"Order created: {order.OrderId}");
});

await messageBus.PublishAsync(new OrderCreated { OrderId = 123 });

Configuration ​

OptionTypeRequiredDefaultDescription
Topicstring✅SNS topic name for publishing
ConnectionStringstringConnection string
CredentialsAWSCredentialsAWS credentials
RegionRegionEndpointAWS region
ServiceUrlstringCustom endpoint (e.g. Floci)
CanCreateTopicbooltrueAuto-create SNS topic if missing
SubscriptionQueueNamestringRandomSQS queue name (use for durable subscriptions)
SubscriptionQueueAutoDeletebooltrueAuto-delete queue on dispose (set false for durable)
ReadQueueTimeoutTimeSpan20sLong polling timeout
DequeueIntervalTimeSpan1sInterval between dequeue attempts
MessageVisibilityTimeoutTimeSpan?30s (SQS)Message visibility timeout
SqsManagedSseEnabledboolfalseEnable SQS managed encryption (SSE-SQS)
KmsMasterKeyIdstringKMS key ID for encryption (SSE-KMS)
KmsDataKeyReusePeriodSecondsint300KMS key reuse period
TopicResolverFunc<Type, string>Route message types to different topics

For additional options, see SQSMessageBusOptions source.

Architecture ​

The SQSMessageBus uses the SNS fan-out pattern:

  • Publishing: Messages are published to an SNS topic
  • Subscribing: Each subscriber gets its own SQS queue subscribed to the SNS topic
  • Durable Subscriptions: Use SubscriptionQueueName and set SubscriptionQueueAutoDelete = false to persist queues across restarts
  • Policy Management: Queue policies are automatically configured to allow SNS to deliver messages

Durable Subscriptions Example ​

csharp
var messageBus = new SQSMessageBus(o =>
{
    o.ConnectionString = connectionString;
    o.Topic = "events";
    o.SubscriptionQueueName = "order-service-events";
    o.SubscriptionQueueAutoDelete = false; // Queue persists across restarts
});

SQSQueue ​

AWS SQS queue implementation for reliable work item processing.

csharp
using Foundatio.Queues;

var queue = new SQSQueue<WorkItem>(o => o
    .ConnectionString(connectionString)
    .Name("work-items"));

await queue.EnqueueAsync(new WorkItem { Data = "Hello" });
var entry = await queue.DequeueAsync();

Configuration ​

OptionTypeRequiredDefaultDescription
Namestring✅Queue name (a .fifo suffix selects a FIFO queue)
ConnectionStringstringConnection string
RegionRegionEndpointAWS region
CredentialsAWSCredentialsAWS credentials
ServiceUrlstringCustom endpoint (e.g. Floci)
CanCreateQueuebooltrueAuto-create queue
SupportDeadLetterbooltrueCreate and use a -deadletter queue
ReadQueueTimeoutTimeSpan20sLong polling timeout
DequeueIntervalTimeSpan1sInterval between dequeue attempts when the queue is empty
RetryDelayFunc<int, TimeSpan>ExponentialVisibility delay before an abandoned message is retried
SqsManagedSseEnabledboolfalseEnable SQS managed encryption (SSE-SQS)
KmsMasterKeyIdstringKMS key ID for encryption (SSE-KMS)
KmsDataKeyReusePeriodSecondsintKMS data key reuse period, in seconds

For additional options, see SQSQueueOptions source.

Fair Queues and Message Groups ​

SQS fair queues stop one noisy tenant from delaying everyone else in a shared standard queue. They are enabled by sending a MessageGroupId (your tenant or customer id) with each message. Foundatio exposes this as QueueEntryOptions.GroupId:

csharp
// Derive the tenant from the payload once...
var queue = new SQSQueue<ImportRequest>(o => o
    .ConnectionString(connectionString)
    .Name("imports")
    .GroupId(r => r.TenantId));

await queue.EnqueueAsync(importRequest);

// ...or set it per call
await queue.EnqueueAsync(importRequest, new QueueEntryOptions { GroupId = "tenant-123" });

Things to know:

  • A standard queue is enough. No queue setting and no consumer change are needed, and messages in the same group can still be processed in parallel. GroupId on a standard queue does not provide ordering.
  • FIFO queues use the same field for ordering. On a .fifo queue, messages in a group are delivered one at a time in order, and SQS requires a group id on every message. FIFO queues reject a positive per-message DeliveryDelay, and an abandoned message with a RetryDelay holds back the rest of its group until it is retried.
  • Group ids are limited to 128 characters of alphanumerics and punctuation (no spaces).
  • FIFO deduplication follows the queue. A UniqueId is sent as MessageDeduplicationId. Without one, SQS derives the id from the body when the queue has ContentBasedDeduplication enabled; otherwise a random id is generated. The setting is read once per queue, on the first send without a UniqueId, and is not polled. If it is turned off later, the send is retried once with a generated id. If it is turned on later, generated ids keep being sent, which is valid but bypasses content-based deduplication until the queue is reopened.
  • Set it on every message. SQS treats a message without a group id as its own tenant.
  • Consumer concurrency matters. SQS marks a tenant as noisy when it holds more than 10% of in-flight messages (with at least 30 in flight) or more than 10% of recent processing time. SQSQueue receives one message per worker loop, so run enough workers or instances for the in-flight share to be meaningful.
  • Monitor with CloudWatch. Compare ApproximateNumberOfMessagesVisible with the ...InQuietGroups metrics to confirm quiet tenants are not affected.

Dead Letter Behavior ​

SQSQueue creates a <name>-deadletter queue with a native SQS redrive policy, and moves a message there itself once Retries is exceeded. FIFO queues use <name>-deadletter.fifo, because AWS requires the dead-letter queue of a FIFO queue to be a FIFO queue (CreateQueue). Without a dead-letter queue, the message is deleted once Retries is exceeded. If the dead-letter queue can't be resolved, the error is logged and the message stays on the source queue to be retried. GetDeadletterItemsAsync is not supported for SQS; read the dead-letter queue directly. The dead-letter queue uses the same encryption settings as the source queue, and its name must fit the 80-character SQS limit, so a source queue name can be at most 69 characters (including .fifo). Moving a message is at-least-once: the copy is sent before the original is deleted, so a failed delete can leave the message in both queues. RetryDelay is applied as the visibility timeout and capped at the SQS maximum of 12 hours.

Deleting a queue takes up to 60 seconds in SQS, and a send during that window can succeed and then be lost with the queue (DeleteQueue). Stop producers and workers before DeleteQueueAsync and wait at least 60 seconds before reusing the name. After a QueueDoesNotExistException, the cached queue url is cleared so the next call recreates the queue.

Next Steps ​

Released under the Apache 2.0 License.