-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* WithName => WithQueueName and WithName => WithTopicName, to make the fluent api a bit easier to read * - Add new static/dynamic publication configuration to support both startup and late-bound topic publishers. - Make test pass (it fails sometimes for some reason still but let's agree on the shape) * - ContainsKey => TryGetValue - ConfigureAwait * - Push localstack logs to debug for more useful info (e.g. to debug publishes) - Add unique test id to each queue so tests are independent - Switch publisher cache to use concurrent dictionary to protect against reads if a publisher is being added by another thread. * - Fix tests so they don't use conditional access as it doesn't work well with shouldly * - Share SNS publisher between all topic publishers that share a topic name customiser * - Fix some broken xml docs - Add xml docs for new API - Minor renames * - Add interrogation support for dynamic publishers * - Undo unnecessary changes to MessagingConfigurationBuilder - Publish second message to same topic to make sure that works - Add some more docs * - Publish two messages for each tenant to ensure it works * Update src/JustSaying/Fluent/PublishConfig/DynamicMessagePublisher.cs Co-authored-by: Martin Costello <[email protected]> * Update src/JustSaying/Fluent/PublishConfig/DynamicMessagePublisher.cs Co-authored-by: Martin Costello <[email protected]> * Update src/JustSaying/Fluent/TopicPublicationBuilder`1.cs Co-authored-by: Martin Costello <[email protected]> * Update src/JustSaying/Fluent/PublishConfig/DynamicMessagePublisher.cs Co-authored-by: Martin Costello <[email protected]> * Update src/JustSaying/Fluent/PublishConfig/DynamicMessagePublisher.cs Co-authored-by: Martin Costello <[email protected]> * Update src/JustSaying/Fluent/TopicPublicationBuilder`1.cs Co-authored-by: Martin Costello <[email protected]> * Update src/JustSaying/Fluent/TopicPublicationBuilder`1.cs Co-authored-by: Martin Costello <[email protected]> * Update src/JustSaying/Fluent/TopicPublicationBuilder`1.cs Co-authored-by: Martin Costello <[email protected]> * Update src/JustSaying/Fluent/PublishConfig/DynamicPublicationConfiguration.cs Co-authored-by: Martin Costello <[email protected]> * Update src/JustSaying/Fluent/PublishConfig/ITopicPublisher.cs Co-authored-by: Martin Costello <[email protected]> * Update src/JustSaying/Fluent/PublishConfig/StaticPublicationConfiguration.cs Co-authored-by: Martin Costello <[email protected]> * - Add missing xmldoc * - Fix build Co-authored-by: George Kinsman <[email protected]> Co-authored-by: Martin Costello <[email protected]>
- Loading branch information
1 parent
db12efc
commit 002db5b
Showing
25 changed files
with
387 additions
and
87 deletions.
There are no files selected for viewing
74 changes: 74 additions & 0 deletions
74
src/JustSaying/Fluent/PublishConfig/DynamicMessagePublisher.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
using System.Collections.Concurrent; | ||
using JustSaying.Messaging; | ||
using JustSaying.Messaging.Interrogation; | ||
using JustSaying.Models; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace JustSaying.Fluent; | ||
|
||
internal sealed class DynamicMessagePublisher : IMessagePublisher | ||
{ | ||
private readonly ConcurrentDictionary<string, IMessagePublisher> _publisherCache = new(); | ||
private readonly Func<Message, string> _topicNameCustomizer; | ||
private readonly Func<string, StaticPublicationConfiguration> _staticConfigBuilder; | ||
|
||
private readonly ConcurrentDictionary<string, SemaphoreSlim> _topicCreationLocks = new(); | ||
private readonly ILogger<DynamicMessagePublisher> _logger; | ||
|
||
public DynamicMessagePublisher(Func<Message, string> topicNameCustomizer, Func<string, StaticPublicationConfiguration> staticConfigBuilder, ILoggerFactory loggerFactory) | ||
{ | ||
_topicNameCustomizer = topicNameCustomizer; | ||
_staticConfigBuilder = staticConfigBuilder; | ||
_logger = loggerFactory.CreateLogger<DynamicMessagePublisher>(); | ||
} | ||
|
||
public InterrogationResult Interrogate() | ||
{ | ||
var pairs = _publisherCache.Keys.OrderBy(x => x) | ||
.ToDictionary(x => x, x => _publisherCache[x].Interrogate()); | ||
|
||
return new InterrogationResult(new | ||
{ | ||
Publishers = pairs | ||
}); | ||
} | ||
|
||
public Task StartAsync(CancellationToken stoppingToken) | ||
{ | ||
return Task.CompletedTask; | ||
} | ||
|
||
public async Task PublishAsync(Message message, PublishMetadata metadata, CancellationToken cancellationToken) | ||
{ | ||
var topicName = _topicNameCustomizer(message); | ||
if (_publisherCache.TryGetValue(topicName, out var publisher)) | ||
{ | ||
await publisher.PublishAsync(message, metadata, cancellationToken).ConfigureAwait(false); | ||
return; | ||
} | ||
|
||
var lockObj = _topicCreationLocks.GetOrAdd(topicName, _ => new SemaphoreSlim(1, 1)); | ||
|
||
_logger.LogDebug("Publisher for topic {TopicName} not found, waiting on creation lock", topicName); | ||
await lockObj.WaitAsync(cancellationToken).ConfigureAwait(false); | ||
if (_publisherCache.TryGetValue(topicName, out var thePublisher)) | ||
{ | ||
_logger.LogDebug("Lock re-entrancy detected, returning existing publisher"); | ||
await thePublisher.PublishAsync(message, metadata, cancellationToken).ConfigureAwait(false); | ||
return; | ||
} | ||
|
||
_logger.LogDebug("Lock acquired to initialize topic {TopicName}", topicName); | ||
var config = _staticConfigBuilder(topicName); | ||
_logger.LogDebug("Executing startup task for topic {TopicName}", topicName); | ||
await config.StartupTask(cancellationToken).ConfigureAwait(false); | ||
|
||
_ = _publisherCache.TryAdd(topicName, config.Publisher); | ||
|
||
_logger.LogDebug("Publishing message on newly created topic {TopicName}", topicName); | ||
await config.Publisher.PublishAsync(message, metadata, cancellationToken).ConfigureAwait(false); | ||
} | ||
|
||
public Task PublishAsync(Message message, CancellationToken cancellationToken) | ||
=> PublishAsync(message, null, cancellationToken); | ||
} |
30 changes: 30 additions & 0 deletions
30
src/JustSaying/Fluent/PublishConfig/DynamicPublicationConfiguration.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using System.ComponentModel; | ||
using System.Xml.Linq; | ||
using JustSaying.AwsTools; | ||
using JustSaying.AwsTools.QueueCreation; | ||
using JustSaying.Messaging; | ||
using JustSaying.Models; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace JustSaying.Fluent; | ||
|
||
internal sealed class DynamicPublicationConfiguration : ITopicPublisher | ||
{ | ||
public DynamicPublicationConfiguration(IMessagePublisher publisher) | ||
{ | ||
Publisher = publisher; | ||
} | ||
|
||
public Func<CancellationToken, Task> StartupTask => _ => Task.CompletedTask; | ||
public IMessagePublisher Publisher { get; } | ||
|
||
public static DynamicPublicationConfiguration Build<T>( | ||
Func<Message, string> topicNameCustomizer, | ||
Func<string, StaticPublicationConfiguration> staticConfigBuilder, | ||
ILoggerFactory loggerFactory) | ||
{ | ||
var publisher = new DynamicMessagePublisher(topicNameCustomizer, staticConfigBuilder, loggerFactory); | ||
|
||
return new DynamicPublicationConfiguration(publisher); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
using JustSaying.Messaging; | ||
|
||
namespace JustSaying.Fluent; | ||
|
||
internal interface ITopicPublisher | ||
{ | ||
Func<CancellationToken, Task> StartupTask { get; } | ||
IMessagePublisher Publisher { get; } | ||
} |
87 changes: 87 additions & 0 deletions
87
src/JustSaying/Fluent/PublishConfig/StaticPublicationConfiguration.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using Amazon; | ||
using Amazon.Internal; | ||
using Amazon.SimpleNotificationService; | ||
using Amazon.SimpleNotificationService.Model; | ||
using JustSaying.AwsTools; | ||
using JustSaying.AwsTools.MessageHandling; | ||
using JustSaying.AwsTools.QueueCreation; | ||
using JustSaying.Messaging; | ||
using Microsoft.Extensions.Logging; | ||
|
||
#pragma warning disable CS0618 | ||
|
||
namespace JustSaying.Fluent; | ||
|
||
internal sealed class StaticPublicationConfiguration : ITopicPublisher | ||
{ | ||
public Func<CancellationToken, Task> StartupTask { get; } | ||
public IMessagePublisher Publisher { get; } | ||
|
||
public StaticPublicationConfiguration( | ||
Func<CancellationToken, Task> startupTask, | ||
IMessagePublisher publisher) | ||
{ | ||
StartupTask = startupTask; | ||
Publisher = publisher; | ||
} | ||
|
||
public static StaticPublicationConfiguration Build<T>( | ||
string topicName, | ||
Dictionary<string, string> tags, | ||
SnsWriteConfiguration writeConfiguration, | ||
IAmazonSimpleNotificationService snsClient, | ||
ILoggerFactory loggerFactory, | ||
JustSayingBus bus) | ||
{ | ||
var readConfiguration = new SqsReadConfiguration(SubscriptionType.ToTopic) | ||
{ | ||
TopicName = topicName | ||
}; | ||
|
||
readConfiguration.ApplyTopicNamingConvention<T>(bus.Config.TopicNamingConvention); | ||
|
||
var eventPublisher = new SnsMessagePublisher( | ||
snsClient, | ||
bus.SerializationRegister, | ||
loggerFactory, | ||
bus.Config.MessageSubjectProvider) | ||
{ | ||
MessageResponseLogger = bus.Config.MessageResponseLogger, | ||
}; | ||
|
||
var snsTopic = new SnsTopicByName( | ||
readConfiguration.TopicName, | ||
snsClient, | ||
loggerFactory) | ||
{ | ||
Tags = tags | ||
}; | ||
|
||
async Task StartupTask(CancellationToken cancellationToken) | ||
{ | ||
if (writeConfiguration.Encryption != null) | ||
{ | ||
await snsTopic.CreateWithEncryptionAsync(writeConfiguration.Encryption, cancellationToken) | ||
.ConfigureAwait(false); | ||
} | ||
else | ||
{ | ||
await snsTopic.CreateAsync(cancellationToken).ConfigureAwait(false); | ||
} | ||
|
||
await snsTopic.EnsurePolicyIsUpdatedAsync(bus.Config.AdditionalSubscriberAccounts) | ||
.ConfigureAwait(false); | ||
|
||
await snsTopic.ApplyTagsAsync(cancellationToken).ConfigureAwait(false); | ||
|
||
eventPublisher.Arn = snsTopic.Arn; | ||
|
||
loggerFactory.CreateLogger<StaticPublicationConfiguration>().LogInformation( | ||
"Created SNS topic publisher on topic '{TopicName}' for message type '{MessageType}'.", | ||
snsTopic.TopicName, | ||
typeof(T)); | ||
} | ||
|
||
return new StaticPublicationConfiguration(StartupTask, eventPublisher); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.