Codebelt

Savvyio.Extensions.SimpleQueueService

Use Savvy I/O command queues and integration event buses on top of Amazon SQS and SNS.

.NET 10.0 / .NET 9.0 MIT v5.0.8 9,859 downloads

Overview

Savvyio.Extensions.SimpleQueueService adapts Savvy I/O messaging abstractions to Amazon Simple Queue Service and Amazon Simple Notification Service. It includes an SQS-backed AmazonCommandQueue for ICommand messages and an AmazonEventBus that publishes IIntegrationEvent messages to SNS and subscribes by reading messages from SQS.

The package also supplies shared option types for credentials, endpoints, receive behavior, paired SQS and SNS client configuration, and ARN construction for topic names. Use it when your application already models distributed work as Savvy I/O commands or integration events and needs AWS transport types instead of direct AWS SDK calls.

Key APIs

AmazonCommandQueue is the concrete point-to-point channel for ICommand. SendAsync partitions outgoing messages into SQS batches of up to AmazonMessageOptions.MaxNumberOfMessages, serializes each message through the configured IMarshaller, records the CLR message type in the SQS message attribute named type, and, for FIFO queues, maps the message source and id to the SQS group and deduplication identifiers. ReceiveAsync yields deserialized command messages from the configured queue, and GetHealthCheckTarget returns the IAmazonSQS client used for health probing.

AmazonEventBus is the concrete publish-subscribe channel for IIntegrationEvent. PublishAsync sends the serialized message to the SNS topic identified by message.Source, adds the same type attribute used by the queue implementation, and applies FIFO group and deduplication values when the configured queue URL contains .fifo. SubscribeAsync keeps draining the configured SQS queue and invoking the supplied handler until no more messages are returned or cancellation stops the loop.

AmazonMessageOptions holds the shared transport configuration for both concrete types. Consumers set Credentials, Endpoint, SourceQueue, and the nested ReceiveContext, while ConfigureClient creates one AmazonSQSConfig and one AmazonSimpleNotificationServiceConfig that take precedence over Endpoint when clients are created.

AmazonMessageReceiveOptions controls how SQS retrieval behaves. NumberOfMessagesToTakePerRequest, PollingTimeout, and VisibilityTimeout are clamped to the limits defined by the package, while AssumeMessageProcessed, RemoveProcessedMessages, and UseApproximateNumberOfMessages control automatic acknowledgement, batched deletion of processed messages, and whether the queue is queried for an approximate message count before reading.

ClientConfigExtensions helps inspect the paired client configuration created by AmazonMessageOptions.ConfigureClient. IsValid verifies that the array contains exactly one AmazonSQSConfig and one AmazonSimpleNotificationServiceConfig, while SimpleQueueService and SimpleNotificationService return those typed configurations.

ToSnsUri converts a topic name into an SNS ARN Uri. It uses AmazonResourceNameOptions for partition, region, and account data, and those options validate that the account id is present, numeric, and 12 characters long.

Basic usage

using System;
using System.IO;
using Amazon;
using Amazon.Runtime;
using Codebelt.Extensions.Xunit;
using Savvyio;
using Savvyio.Extensions.SimpleQueueService;
using Savvyio.Extensions.SimpleQueueService.EventDriven;
using Xunit;

namespace MyProject.Tests;

public sealed class AmazonEventBusConfigurationTest : Test
{
    public AmazonEventBusConfigurationTest(ITestOutputHelper output) : base(output) { }

    [Fact]
    public void ConfigureOptions_FifoQueue_BuildsExpectedClients()
    {
        var options = new AmazonEventBusOptions
        {
            Credentials = new BasicAWSCredentials("access-key", "secret-key"),
            Endpoint = RegionEndpoint.EUWest1,
            SourceQueue = new Uri("https://sqs.eu-west-1.amazonaws.com/000000000000/member-events.fifo")
        };
        options.ConfigureClient(_ => { });

        var topicArn = "member-events.fifo".ToSnsUri(o => o.AccountId = "000000000000");
        var bus = new InspectableAmazonEventBus(new ThrowingMarshaller(), options);

        TestOutput.WriteLine($"Topic ARN: {topicArn.OriginalString}");
        TestOutput.WriteLine($"FIFO queue detected: {bus.IsFirstInFirstOut}");

        Assert.True(bus.IsFirstInFirstOut);
        Assert.True(options.ClientConfigurations.IsValid());
        Assert.NotNull(options.ClientConfigurations.SimpleQueueService());
        Assert.NotNull(options.ClientConfigurations.SimpleNotificationService());
        Assert.Equal("arn:aws:sns:eu-west-1:000000000000:member-events.fifo", topicArn.OriginalString);
    }

    private sealed class InspectableAmazonEventBus : AmazonEventBus
    {
        public InspectableAmazonEventBus(IMarshaller marshaller, AmazonEventBusOptions options) : base(marshaller, options) { }

        public bool IsFirstInFirstOut => UseFirstInFirstOut;
    }

    private sealed class ThrowingMarshaller : IMarshaller
    {
        public Stream Serialize<TValue>(TValue value) => throw new NotSupportedException();
        public Stream Serialize(object value, Type inputType) => throw new NotSupportedException();
        public TValue Deserialize<TValue>(Stream data) => throw new NotSupportedException();
        public object Deserialize(Stream data, Type returnType) => throw new NotSupportedException();
    }
}

Use this pattern when you need to prepare an AmazonEventBus or AmazonCommandQueue for a FIFO queue and want one options object to describe both SQS and SNS client setup. It matters because the package derives FIFO behavior from the queue URI and keeps queue settings, topic naming, and paired AWS client configuration aligned.

Installation

dotnet add package Savvyio.Extensions.SimpleQueueService

Usage guidance

Choose this package when your application already represents distributed work as Savvy I/O ICommand or IIntegrationEvent messages and you want concrete AWS transport types with configurable receive behavior, paired client setup, and SNS ARN helpers. If you only need direct AWS SDK calls, or you want IServiceCollection registration instead of manual construction, the AWS SDK itself or the sibling Savvyio.Extensions.DependencyInjection.SimpleQueueService package is the better fit.

Family packages