From 846184508bdc9d9b83425108361e2ba1f5ed5d60 Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Wed, 9 Oct 2024 08:35:23 +0100 Subject: [PATCH 01/15] feat: add an archive test without observablity, to ensure test passes first, ahead of oberservability --- src/Paramore.Brighter/ExternalBusService.cs | 14 +-- src/Paramore.Brighter/InMemoryOutbox.cs | 6 +- .../Archive/When_archiving_from_the_outbox.cs | 109 ++++++++++++++++++ 3 files changed, 119 insertions(+), 10 deletions(-) create mode 100644 tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs diff --git a/src/Paramore.Brighter/ExternalBusService.cs b/src/Paramore.Brighter/ExternalBusService.cs index f8b8dc9b57..f2559c439d 100644 --- a/src/Paramore.Brighter/ExternalBusService.cs +++ b/src/Paramore.Brighter/ExternalBusService.cs @@ -151,7 +151,7 @@ private void Dispose(bool disposing) if (_disposed) return; - if (disposing && _producerRegistry != null) + if (disposing) _producerRegistry.CloseAll(); _disposed = true; } @@ -568,7 +568,7 @@ public void EndBatchAddToOutbox(string batchId, IAmABoxTransactionProvider DispatchedMessages( { ClearExpiredMessages(); - var age = - _timeProvider.GetUtcNow() - dispatchedSince; + var now = _timeProvider.GetUtcNow(); + var age = now - dispatchedSince; return Requests.Values .Where(oe => (oe.TimeFlushed != DateTimeOffset.MinValue) && (oe.TimeFlushed <= age)) .Take(pageSize) @@ -439,7 +439,7 @@ public void MarkDispatched(string id, RequestContext requestContext, DateTimeOff if (Requests.TryGetValue(id, out OutboxEntry? entry)) { - entry.TimeFlushed = dispatchedAt ?? _timeProvider.GetUtcNow().DateTime; + entry.TimeFlushed = dispatchedAt ?? _timeProvider.GetUtcNow(); } } diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs new file mode 100644 index 0000000000..d904bbcc9a --- /dev/null +++ b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Transactions; +using FluentAssertions; +using Microsoft.Extensions.Time.Testing; +using OpenTelemetry; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; +using Paramore.Brighter.Core.Tests.CommandProcessors.TestDoubles; +using Paramore.Brighter.Observability; +using Polly; +using Polly.Registry; +using Xunit; + +namespace Paramore.Brighter.Core.Tests.Observability.Archive; + +public class ExternalServiceBusArchiveObservabilityTests +{ + private readonly List _exportedActivities = new(); + private readonly ExternalBusService _bus; + private readonly Publication _publication; + private readonly FakeTimeProvider _timeProvider; + private RoutingKey _routingKey = new("MyEvent"); + private readonly InMemoryOutbox _outbox; + + public ExternalServiceBusArchiveObservabilityTests() + { + IAmABus internalBus = new InternalBus(); + _timeProvider = new FakeTimeProvider(); + var tracer = new BrighterTracer(_timeProvider); + + var builder = Sdk.CreateTracerProviderBuilder(); + + var traceProvider = builder + .AddSource("Paramore.Brighter.Tests", "Paramore.Brighter") + .ConfigureResource(r => r.AddService("in-memory-tracer")) + .AddInMemoryExporter(_exportedActivities) + .Build(); + + Brighter.CommandProcessor.ClearServiceBus(); + + _publication = new Publication + { + Source = new Uri("http://localhost"), + RequestType = typeof(MyEvent), + Topic = _routingKey, + Type = nameof(MyEvent), + }; + + var producer = new InMemoryProducer(internalBus, _timeProvider) + { + Publication = _publication + }; + + var producerRegistry = + new ProducerRegistry(new Dictionary { { _routingKey, producer } }); + + var retryPolicy = Policy + .Handle() + .Retry(); + + var policyRegistry = new PolicyRegistry { { Brighter.CommandProcessor.RETRYPOLICY, retryPolicy } }; + + var messageMapperRegistry = new MessageMapperRegistry( + new SimpleMessageMapperFactory((_) => new MyEventMessageMapper()), + null); + messageMapperRegistry.Register(); + + _outbox = new InMemoryOutbox(_timeProvider) { Tracer = tracer }; + var archiveProvider = new InMemoryArchiveProvider(); + + _bus = new ExternalBusService( + producerRegistry, + policyRegistry, + messageMapperRegistry, + new EmptyMessageTransformerFactory(), + new EmptyMessageTransformerFactoryAsync(), + tracer, + _outbox, + archiveProvider, + timeProvider:_timeProvider); + } + + [Fact] + public void When_archiving_from_the_outbox() + { + var context = new RequestContext(); + + //add and clear message + var myEvent = new MyEvent(); + var myMessage = new MyEventMessageMapper().MapToMessage(myEvent, _publication); + _bus.AddToOutbox(myMessage, context); + _bus.ClearOutbox([myMessage.Id], context); + + //se should have an entry in the outbox + _outbox.EntryCount.Should().Be(1); + + //allow time to pass + _timeProvider.Advance(TimeSpan.FromSeconds(300)); + + //archive + _bus.Archive(TimeSpan.FromSeconds(100), context); + + //should be no messages in the outbox + _outbox.EntryCount.Should().Be(0); + + } +} From 358d03b8b6488ff37429d933cf29bb980579c385 Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Fri, 11 Oct 2024 10:35:42 +0100 Subject: [PATCH 02/15] chore: switch branch; commit to save wip --- .../BrighterSemanticConventions.cs | 1 + .../Observability/BrighterSpanExtensions.cs | 1 + .../Observability/BrighterTracer.cs | 21 +++++++++++++++ .../CommandProcessorSpanOperation.cs | 3 ++- .../Archive/When_archiving_from_the_outbox.cs | 21 ++++++++++++++- ...n_Clearing_A_Message_A_Span_Is_Exported.cs | 26 +++++++++---------- 6 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/Paramore.Brighter/Observability/BrighterSemanticConventions.cs b/src/Paramore.Brighter/Observability/BrighterSemanticConventions.cs index fb158fb776..3f2f67778e 100644 --- a/src/Paramore.Brighter/Observability/BrighterSemanticConventions.cs +++ b/src/Paramore.Brighter/Observability/BrighterSemanticConventions.cs @@ -29,6 +29,7 @@ namespace Paramore.Brighter.Observability; /// public static class BrighterSemanticConventions { + public const string ArchiveMessages = "paramore.brighter.archive_messages"; public const string CeSource = "cloudevents.event_source"; public const string CeMessageId = "cloudevents.event_id"; public const string CeVersion = "cloudevents.event_spec_version"; diff --git a/src/Paramore.Brighter/Observability/BrighterSpanExtensions.cs b/src/Paramore.Brighter/Observability/BrighterSpanExtensions.cs index 2c858d3cfc..9bc5e89a22 100644 --- a/src/Paramore.Brighter/Observability/BrighterSpanExtensions.cs +++ b/src/Paramore.Brighter/Observability/BrighterSpanExtensions.cs @@ -41,6 +41,7 @@ public static class BrighterSpanExtensions CommandProcessorSpanOperation.Publish => "publish", CommandProcessorSpanOperation.Send => "send", CommandProcessorSpanOperation.Clear => "clear", + CommandProcessorSpanOperation.Archive => "archive", _ => throw new ArgumentOutOfRangeException(nameof(operation), operation, null) }; diff --git a/src/Paramore.Brighter/Observability/BrighterTracer.cs b/src/Paramore.Brighter/Observability/BrighterTracer.cs index 5f923d5667..a39216c78d 100644 --- a/src/Paramore.Brighter/Observability/BrighterTracer.cs +++ b/src/Paramore.Brighter/Observability/BrighterTracer.cs @@ -285,6 +285,27 @@ public void Dispose() return activity; } + + public Activity? CreateArchiveSpan( + Activity? parentActivity, + string? messageId = null, + InstrumentationOptions options = InstrumentationOptions.All) + { + var spanName = $"{BrighterSemanticConventions.ArchiveMessages} {CommandProcessorSpanOperation.Archive.ToSpanName()}"; + var kind = ActivityKind.Producer; + var parentId = parentActivity?.Id; + var now = _timeProvider.GetUtcNow(); + + var activity = ActivitySource.StartActivity( + name: spanName, + kind: kind, + parentId: parentId, + startTime: now); + + Activity.Current = activity; + + return activity; + } /// /// Create a span for a batch of messages to be cleared diff --git a/src/Paramore.Brighter/Observability/CommandProcessorSpanOperation.cs b/src/Paramore.Brighter/Observability/CommandProcessorSpanOperation.cs index f0dabbcd90..19f29e8b63 100644 --- a/src/Paramore.Brighter/Observability/CommandProcessorSpanOperation.cs +++ b/src/Paramore.Brighter/Observability/CommandProcessorSpanOperation.cs @@ -33,5 +33,6 @@ public enum CommandProcessorSpanOperation Create = 1, // A batch operation, such as publishing an event or clearing a message Publish = 2, // Publish an event Deposit = 3, // Deposit a message in the outbox - Clear = 4 // Clear a message from the outbox + Clear = 4, // Clear a message from the outbox + Archive = 5 //Archive a message from the outbox } diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs index d904bbcc9a..d2dc537f71 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Transactions; using FluentAssertions; using Microsoft.Extensions.Time.Testing; @@ -23,6 +24,7 @@ public class ExternalServiceBusArchiveObservabilityTests private readonly FakeTimeProvider _timeProvider; private RoutingKey _routingKey = new("MyEvent"); private readonly InMemoryOutbox _outbox; + private readonly TracerProvider _traceProvider; public ExternalServiceBusArchiveObservabilityTests() { @@ -32,7 +34,7 @@ public ExternalServiceBusArchiveObservabilityTests() var builder = Sdk.CreateTracerProviderBuilder(); - var traceProvider = builder + _traceProvider = builder .AddSource("Paramore.Brighter.Tests", "Paramore.Brighter") .ConfigureResource(r => r.AddService("in-memory-tracer")) .AddInMemoryExporter(_exportedActivities) @@ -85,7 +87,10 @@ public ExternalServiceBusArchiveObservabilityTests() [Fact] public void When_archiving_from_the_outbox() { + var parentActivity = new ActivitySource("Paramore.Brighter.Tests").StartActivity("BrighterTracerSpanTests"); + var context = new RequestContext(); + context.Span = parentActivity; //add and clear message var myEvent = new MyEvent(); @@ -105,5 +110,19 @@ public void When_archiving_from_the_outbox() //should be no messages in the outbox _outbox.EntryCount.Should().Be(0); + parentActivity?.Stop(); + + _traceProvider.ForceFlush(); + + //We should have exported matching activities + _exportedActivities.Count.Should().Be(5); + + _exportedActivities.Any(a => a.Source.Name == "Paramore.Brighter").Should().BeTrue(); + + //there should be a create span for the batch + var createActivity = _exportedActivities.Single(a => a.DisplayName == $"{BrighterSemanticConventions.ArchiveMessages} {CommandProcessorSpanOperation.Archive.ToSpanName()}"); + createActivity.Should().NotBeNull(); + createActivity.ParentId.Should().Be(parentActivity?.Id); + } } diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported.cs index b51f772600..fadb9335af 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported.cs @@ -143,14 +143,14 @@ public void When_Clearing_A_Message_A_Span_Is_Exported() var message = _internalBus.Stream(new RoutingKey("MyEvent")).Single(); var depositEvent = events.Single(e => e.Name == OutboxDbOperation.Get.ToSpanName()); depositEvent.Tags.Any(a => a.Value != null && a.Key == BrighterSemanticConventions.OutboxSharedTransaction && (bool)a.Value == false).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.OutboxType && (string)a.Value == "sync" ).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageId && (string)a.Value == message.Id ).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessagingDestination && (RoutingKey)a.Value == message.Header.Topic).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.OutboxType && a.Value as string == "sync" ).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageId && a.Value as string == message.Id ).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessagingDestination && a.Value as string == message.Header.Topic.Value).Should().BeTrue(); depositEvent.Tags.Any(a => a is { Value: not null, Key: BrighterSemanticConventions.MessageBodySize } && (int)a.Value == message.Body.Bytes.Length).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageBody && (string)a.Value == message.Body.Value).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageType && (string)a.Value == message.Header.MessageType.ToString()).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessagingDestinationPartitionId && (string)a.Value == message.Header.PartitionKey).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageHeaders && (string)a.Value == JsonSerializer.Serialize(message.Header)).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageBody && a.Value as string == message.Body.Value).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageType && a.Value as string == message.Header.MessageType.ToString()).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessagingDestinationPartitionId && a.Value as string == message.Header.PartitionKey).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageHeaders && a.Value as string == JsonSerializer.Serialize(message.Header)).Should().BeTrue(); //there should be a span in the Db for retrieving the message var outBoxActivity = _exportedActivities.Single(a => a.DisplayName == $"{OutboxDbOperation.Get.ToSpanName()} {InMemoryAttributes.DbName} {InMemoryAttributes.DbTable}"); @@ -164,15 +164,15 @@ public void When_Clearing_A_Message_A_Span_Is_Exported() producerActivity.ParentId.Should().Be(clearActivity.Id); producerActivity.Kind.Should().Be(ActivityKind.Producer); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessagingOperationType && (string)t.Value == CommandProcessorSpanOperation.Publish.ToSpanName()).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageId && (string)t.Value == message.Id).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageType && (string)t.Value == message.Header.MessageType.ToString()).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessagingOperationType && t.Value as string == CommandProcessorSpanOperation.Publish.ToSpanName()).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageId && t.Value as string == message.Id).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageType && t.Value as string == message.Header.MessageType.ToString()).Should().BeTrue(); producerActivity.TagObjects.Any(t => t is { Value: not null, Key: BrighterSemanticConventions.MessagingDestination } && t.Value.ToString() == "MyEvent").Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessagingDestinationPartitionId && (string)t.Value == message.Header.PartitionKey).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessagingDestinationPartitionId && t.Value as string == message.Header.PartitionKey).Should().BeTrue(); producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageHeaders && (string)t.Value == JsonSerializer.Serialize(message.Header)).Should().BeTrue(); producerActivity.TagObjects.Any(t => t is { Value: not null, Key: BrighterSemanticConventions.MessageBodySize } && (int)t.Value == message.Body.Bytes.Length).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageBody && (string)t.Value == message.Body.Value).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.ConversationId && (string)t.Value == message.Header.CorrelationId).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageBody && t.Value as string == message.Body.Value).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.ConversationId && t.Value as string == message.Header.CorrelationId).Should().BeTrue(); producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.CeMessageId && (string)t.Value == message.Id).Should().BeTrue(); producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.CeSource && (Uri)t.Value == _producer.Publication.Source).Should().BeTrue(); From 9b4acbc0b5b79b6a80921bed4e21f88d2a7b145a Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Fri, 11 Oct 2024 17:34:29 +0100 Subject: [PATCH 03/15] chore: switch to another device --- Directory.Packages.props | 2 +- src/Paramore.Brighter/ExternalBusService.cs | 2 ++ src/Paramore.Brighter/Observability/BrighterTracer.cs | 8 +++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 4c0bec4129..560cd7a6a8 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -40,7 +40,7 @@ - + diff --git a/src/Paramore.Brighter/ExternalBusService.cs b/src/Paramore.Brighter/ExternalBusService.cs index f2559c439d..766d1d253f 100644 --- a/src/Paramore.Brighter/ExternalBusService.cs +++ b/src/Paramore.Brighter/ExternalBusService.cs @@ -250,6 +250,8 @@ public void AddToOutbox( /// The request context for the pipeline public void Archive(TimeSpan dispatchedSince, RequestContext requestContext) { + var span = _tracer?.(CommandProcessorSpanOperation.Create, requestContext?.Span, options: _instrumentationOptions); + try { if (_outBox is null) throw new ArgumentException(NoSyncOutboxError); diff --git a/src/Paramore.Brighter/Observability/BrighterTracer.cs b/src/Paramore.Brighter/Observability/BrighterTracer.cs index a39216c78d..26b7b9ee0a 100644 --- a/src/Paramore.Brighter/Observability/BrighterTracer.cs +++ b/src/Paramore.Brighter/Observability/BrighterTracer.cs @@ -286,9 +286,15 @@ public void Dispose() return activity; } + /// + /// Creates a span for an archive operation. Because a sweeper may not create an externa bus, but just use the archiver directly, we + /// check for this existing and then recreate directly in the archive provider if it does not exist + /// + /// A parent activity that called this one + /// The for how deep should the instrumentation go? + /// public Activity? CreateArchiveSpan( Activity? parentActivity, - string? messageId = null, InstrumentationOptions options = InstrumentationOptions.All) { var spanName = $"{BrighterSemanticConventions.ArchiveMessages} {CommandProcessorSpanOperation.Archive.ToSpanName()}"; From 1fa1ee62587f89480b21e29fe21216566e5edbf9 Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Tue, 15 Oct 2024 15:09:06 +0100 Subject: [PATCH 04/15] feat: we need a create span for the archive batch, if issued through the service bus. Presumably **your** archiver would have to do the same. --- src/Paramore.Brighter/ExternalBusService.cs | 7 +++- .../Observability/IAmABrighterTracer.cs | 38 ++++++++++++------- .../Archive/When_archiving_from_the_outbox.cs | 2 +- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/Paramore.Brighter/ExternalBusService.cs b/src/Paramore.Brighter/ExternalBusService.cs index 766d1d253f..c69b6db403 100644 --- a/src/Paramore.Brighter/ExternalBusService.cs +++ b/src/Paramore.Brighter/ExternalBusService.cs @@ -250,7 +250,8 @@ public void AddToOutbox( /// The request context for the pipeline public void Archive(TimeSpan dispatchedSince, RequestContext requestContext) { - var span = _tracer?.(CommandProcessorSpanOperation.Create, requestContext?.Span, options: _instrumentationOptions); + //This is a archive span parent; we expect individual archiving operations for messages to have their own spans + var span = _tracer?.CreateArchiveSpan(requestContext.Span, options: _instrumentationOptions); try { @@ -285,6 +286,10 @@ public void Archive(TimeSpan dispatchedSince, RequestContext requestContext) s_logger.LogError(e, "Error while archiving from the outbox"); throw; } + finally + { + _tracer?.EndSpan(span); + } } /// diff --git a/src/Paramore.Brighter/Observability/IAmABrighterTracer.cs b/src/Paramore.Brighter/Observability/IAmABrighterTracer.cs index df27a6a6f1..3877298a90 100644 --- a/src/Paramore.Brighter/Observability/IAmABrighterTracer.cs +++ b/src/Paramore.Brighter/Observability/IAmABrighterTracer.cs @@ -69,6 +69,15 @@ public interface IAmABrighterTracer : IDisposable InstrumentationOptions options = InstrumentationOptions.All ) where TRequest : class, IRequest; + /// + /// Creates a span for an archive operation. Because a sweeper may not create an externa bus, but just use the archiver directly, we + /// check for this existing and then recreate directly in the archive provider if it does not exist + /// + /// A parent activity that called this one + /// The for how deep should the instrumentation go? + /// + Activity? CreateArchiveSpan(Activity? parentActivity, InstrumentationOptions options = InstrumentationOptions.All); + /// /// Create a span for a request in CommandProcessor /// @@ -83,6 +92,21 @@ public interface IAmABrighterTracer : IDisposable ActivityLink[]? links = null, InstrumentationOptions options = InstrumentationOptions.All ) where TRequest : class, IRequest; + + /// + /// The parent span for the message pump. This is the entry point for the message pump + /// + /// The . This should be Begin or End + /// The for this span + /// The that we are receiving from + /// The for how deep should the instrumentation go? + /// A span (or dotnet Activity) for the current request named request.name operation.name + /// How deep should the instrumentation go? + Activity? CreateMessagePumpSpan( + MessagePumpSpanOperation operation, + RoutingKey topic, + MessagingSystem messagingSystem, + InstrumentationOptions options = InstrumentationOptions.All); /// /// The for this span @@ -159,18 +183,4 @@ public interface IAmABrighterTracer : IDisposable /// /// void LinkSpans(ConcurrentDictionary handlerSpans); - - /// - /// The parent span for the message pump. This is the entry point for the message pump - /// - /// The . This should be Begin or End - /// The for this span - /// The that we are receiving from - /// The for how deep should the instrumentation go? - /// A span (or dotnet Activity) for the current request named request.name operation.name - Activity? CreateMessagePumpSpan( - MessagePumpSpanOperation operation, - RoutingKey topic, - MessagingSystem messagingSystem, - InstrumentationOptions instrumentationOptions = InstrumentationOptions.All); } diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs index d2dc537f71..4f8c0178a5 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs @@ -115,7 +115,7 @@ public void When_archiving_from_the_outbox() _traceProvider.ForceFlush(); //We should have exported matching activities - _exportedActivities.Count.Should().Be(5); + _exportedActivities.Count.Should().Be(6); _exportedActivities.Any(a => a.Source.Name == "Paramore.Brighter").Should().BeTrue(); From c3e900bec10e821bd1308ccf857df9828860e292 Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Sun, 27 Oct 2024 12:15:52 +0000 Subject: [PATCH 05/15] fix: missing mark dispatched in clear otel checks --- src/Paramore.Brighter/ExternalBusService.cs | 7 +- src/Paramore.Brighter/InMemoryOutbox.cs | 77 ++++++++++++++++--- ...n_Clearing_A_Message_A_Span_Is_Exported.cs | 12 ++- 3 files changed, 78 insertions(+), 18 deletions(-) diff --git a/src/Paramore.Brighter/ExternalBusService.cs b/src/Paramore.Brighter/ExternalBusService.cs index c69b6db403..091adc3205 100644 --- a/src/Paramore.Brighter/ExternalBusService.cs +++ b/src/Paramore.Brighter/ExternalBusService.cs @@ -251,7 +251,9 @@ public void AddToOutbox( public void Archive(TimeSpan dispatchedSince, RequestContext requestContext) { //This is a archive span parent; we expect individual archiving operations for messages to have their own spans - var span = _tracer?.CreateArchiveSpan(requestContext.Span, options: _instrumentationOptions); + var parentSpan = requestContext.Span; + var createSpan = _tracer?.CreateArchiveSpan(requestContext.Span, options: _instrumentationOptions); + requestContext.Span = createSpan; try { @@ -288,7 +290,8 @@ public void Archive(TimeSpan dispatchedSince, RequestContext requestContext) } finally { - _tracer?.EndSpan(span); + _tracer?.EndSpan(createSpan); + requestContext.Span = parentSpan; } } diff --git a/src/Paramore.Brighter/InMemoryOutbox.cs b/src/Paramore.Brighter/InMemoryOutbox.cs index a6f6c80a08..6e54fa33f4 100644 --- a/src/Paramore.Brighter/InMemoryOutbox.cs +++ b/src/Paramore.Brighter/InMemoryOutbox.cs @@ -214,6 +214,8 @@ public Task AddAsync( IAmABoxTransactionProvider? transactionProvider = null, CancellationToken cancellationToken = default) { + //NOTE: As we call Add, don't create telemetry here + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); if (cancellationToken.IsCancellationRequested) @@ -241,11 +243,11 @@ public void Delete(string[] messageIds, RequestContext? requestContext, Dictiona { foreach (string messageId in messageIds) { - Requests.TryRemove(messageId, out _); + Delete(messageId); } } - /// + /// /// Deletes the messages from the Outbox /// /// The ids of the messages to delete @@ -282,13 +284,26 @@ public IEnumerable DispatchedMessages( Dictionary? args = null) { ClearExpiredMessages(); + + var span = Tracer?.CreateDbSpan( + new OutboxSpanInfo(DbSystem.Brighter, InMemoryAttributes.DbName, OutboxDbOperation.DispatchedMessages, InMemoryAttributes.DbTable), + requestContext?.Span, + options: _instrumentationOptions + ); - var now = _timeProvider.GetUtcNow(); - var age = now - dispatchedSince; - return Requests.Values - .Where(oe => (oe.TimeFlushed != DateTimeOffset.MinValue) && (oe.TimeFlushed <= age)) - .Take(pageSize) - .Select(oe => oe.Message).ToArray(); + try + { + var now = _timeProvider.GetUtcNow(); + var age = now - dispatchedSince; + return Requests.Values + .Where(oe => (oe.TimeFlushed != DateTimeOffset.MinValue) && (oe.TimeFlushed <= age)) + .Take(pageSize) + .Select(oe => oe.Message).ToArray(); + } + finally + { + Tracer?.EndSpan(span); + } } /// @@ -309,6 +324,8 @@ public Task> DispatchedMessagesAsync(TimeSpan dispatchedSin Dictionary? args = null, CancellationToken cancellationToken = default) { + //NOTE: As we call DispatchedMessages, don't create telemetry here + return Task.FromResult(DispatchedMessages(dispatchedSince, requestContext, pageSize, pageNumber, outboxTimeout, args)); @@ -391,6 +408,8 @@ public Task MarkDispatchedAsync( Dictionary? args = null, CancellationToken cancellationToken = default) { + //NOTE: We don't create a span here as we just call the sync method + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); MarkDispatched(id, requestContext, dispatchedAt); @@ -415,6 +434,8 @@ public Task MarkDispatchedAsync( Dictionary? args = null, CancellationToken cancellationToken = default) { + //NOTE: We don't create a span here as we just call the sync method + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); ids.Each((id) => MarkDispatched(id, requestContext, dispatchedAt)); @@ -436,10 +457,23 @@ public void MarkDispatched(string id, RequestContext requestContext, DateTimeOff Dictionary? args = null) { ClearExpiredMessages(); + + var span = Tracer?.CreateDbSpan( + new OutboxSpanInfo(DbSystem.Brighter, InMemoryAttributes.DbName, OutboxDbOperation.MarkDispatched, InMemoryAttributes.DbTable), + requestContext?.Span, + options: _instrumentationOptions + ); - if (Requests.TryGetValue(id, out OutboxEntry? entry)) + try { - entry.TimeFlushed = dispatchedAt ?? _timeProvider.GetUtcNow(); + if (Requests.TryGetValue(id, out OutboxEntry? entry)) + { + entry.TimeFlushed = dispatchedAt ?? _timeProvider.GetUtcNow(); + } + } + finally + { + Tracer?.EndSpan(span); } } @@ -502,12 +536,31 @@ public Task> OutstandingMessagesAsync( Dictionary? args = null, CancellationToken cancellationToken = default) { - var tcs = new TaskCompletionSource>(TaskCreationOptions - .RunContinuationsAsynchronously); + //NOTE: We don't create a span here as we just call the sync method + + var tcs = new TaskCompletionSource>(TaskCreationOptions.RunContinuationsAsynchronously); tcs.SetResult(OutstandingMessages(dispatchedSince, requestContext, pageSize, pageNumber, args)); return tcs.Task; } + + private void Delete(string messageId, RequestContext? requestContext = null) + { + var span = Tracer?.CreateDbSpan( + new OutboxSpanInfo(DbSystem.Brighter, InMemoryAttributes.DbName, OutboxDbOperation.Delete, InMemoryAttributes.DbTable), + requestContext?.Span, + options: _instrumentationOptions + ); + + try + { + Requests.TryRemove(messageId, out _); + } + finally + { + Tracer?.EndSpan(span); + } + } } } diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported.cs index fadb9335af..4826fc22e5 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported.cs @@ -121,7 +121,7 @@ public void When_Clearing_A_Message_A_Span_Is_Exported() _traceProvider.ForceFlush(); //assert - _exportedActivities.Count.Should().Be(7); + _exportedActivities.Count.Should().Be(8); _exportedActivities.Any(a => a.Source.Name == "Paramore.Brighter").Should().BeTrue(); //there should be a create span for the batch @@ -129,7 +129,6 @@ public void When_Clearing_A_Message_A_Span_Is_Exported() createActivity.Should().NotBeNull(); createActivity.ParentId.Should().Be(parentActivity?.Id); createActivity.Tags.Any(t => t is { Key: BrighterSemanticConventions.Operation, Value: "clear" }).Should().BeTrue(); - //there should be a clear span for each message id var clearActivity = _exportedActivities.Single(a => a.DisplayName == $"{BrighterSemanticConventions.ClearMessages} {CommandProcessorSpanOperation.Clear.ToSpanName()}"); @@ -145,7 +144,7 @@ public void When_Clearing_A_Message_A_Span_Is_Exported() depositEvent.Tags.Any(a => a.Value != null && a.Key == BrighterSemanticConventions.OutboxSharedTransaction && (bool)a.Value == false).Should().BeTrue(); depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.OutboxType && a.Value as string == "sync" ).Should().BeTrue(); depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageId && a.Value as string == message.Id ).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessagingDestination && a.Value as string == message.Header.Topic.Value).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessagingDestination && a.Value?.ToString() == message.Header.Topic.Value).Should().BeTrue(); depositEvent.Tags.Any(a => a is { Value: not null, Key: BrighterSemanticConventions.MessageBodySize } && (int)a.Value == message.Body.Bytes.Length).Should().BeTrue(); depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageBody && a.Value as string == message.Body.Value).Should().BeTrue(); depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageType && a.Value as string == message.Header.MessageType.ToString()).Should().BeTrue(); @@ -199,6 +198,11 @@ public void When_Clearing_A_Message_A_Span_Is_Exported() produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.CeSubject && (string)t.Value == _producer.Publication.Subject).Should().BeTrue(); produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.CeType && (string)t.Value == _producer.Publication.Type).Should().BeTrue(); - //TODO: There should be a span event to mark as dispatched + //There should be a span event to mark as dispatched + var markAsDispatchedActivity = _exportedActivities.Single(a => a.DisplayName == $"{OutboxDbOperation.MarkDispatched.ToSpanName()} {InMemoryAttributes.DbName} {InMemoryAttributes.DbTable}"); + markAsDispatchedActivity.Tags.Any(t => t.Key == BrighterSemanticConventions.DbOperation && t.Value == OutboxDbOperation.MarkDispatched.ToSpanName()).Should().BeTrue(); + markAsDispatchedActivity.Tags.Any(t => t.Key == BrighterSemanticConventions.DbTable && t.Value == InMemoryAttributes.DbTable).Should().BeTrue(); + markAsDispatchedActivity.Tags.Any(t => t.Key == BrighterSemanticConventions.DbSystem && t.Value == DbSystem.Brighter.ToDbName()).Should().BeTrue(); + markAsDispatchedActivity.Tags.Any(t => t.Key == BrighterSemanticConventions.DbName && t.Value == InMemoryAttributes.DbName).Should().BeTrue(); } } From b327a981892ff7456705e7b1fcb09a615e0f661c Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Sun, 27 Oct 2024 14:19:15 +0000 Subject: [PATCH 06/15] feat: add tagobjects for archive batch --- src/Paramore.Brighter/ExternalBusService.cs | 14 +++--- .../BrighterSemanticConventions.cs | 1 + .../Observability/BrighterTracer.cs | 19 ++++++-- .../Observability/IAmABrighterTracer.cs | 13 +++--- src/Paramore.Brighter/OutboxArchiver.cs | 46 +++---------------- .../Archive/When_archiving_from_the_outbox.cs | 22 +++++++-- 6 files changed, 56 insertions(+), 59 deletions(-) diff --git a/src/Paramore.Brighter/ExternalBusService.cs b/src/Paramore.Brighter/ExternalBusService.cs index 091adc3205..6350519c78 100644 --- a/src/Paramore.Brighter/ExternalBusService.cs +++ b/src/Paramore.Brighter/ExternalBusService.cs @@ -11,6 +11,8 @@ using Polly; using Polly.Registry; +// ReSharper disable StaticMemberInGenericType + namespace Paramore.Brighter { /// @@ -119,7 +121,7 @@ public ExternalBusService(IAmAProducerRegistry producerRegistry, _transformPipelineBuilderAsync = new TransformPipelineBuilderAsync(mapperRegistryAsync, messageTransformerFactoryAsync); - //default to in-memory; expectation for a in memory box is Message and CommittableTransaction + //default to in-memory; expectation for an in memory box is Message and CommittableTransaction outbox ??= new InMemoryOutbox(TimeProvider.System); outbox.Tracer = tracer; @@ -250,9 +252,9 @@ public void AddToOutbox( /// The request context for the pipeline public void Archive(TimeSpan dispatchedSince, RequestContext requestContext) { - //This is a archive span parent; we expect individual archiving operations for messages to have their own spans + //This is an archive span parent; we expect individual archiving operations for messages to have their own spans var parentSpan = requestContext.Span; - var createSpan = _tracer?.CreateArchiveSpan(requestContext.Span, options: _instrumentationOptions); + var createSpan = _tracer.CreateArchiveSpan(requestContext.Span, dispatchedSince, options: _instrumentationOptions); requestContext.Span = createSpan; try @@ -290,7 +292,7 @@ public void Archive(TimeSpan dispatchedSince, RequestContext requestContext) } finally { - _tracer?.EndSpan(createSpan); + _tracer.EndSpan(createSpan); requestContext.Span = parentSpan; } } @@ -565,7 +567,7 @@ public void CreateRequestFromMessage(Message message, RequestContext? /// /// Commence a batch of outbox messages to add /// - /// The Id of the new batch + /// The ID of the new batch public string StartBatchAddToOutbox() { var batchId = Guid.NewGuid().ToString(); @@ -597,7 +599,7 @@ public void EndBatchAddToOutbox(string batchId, IAmABoxTransactionProvider /// Flush the batch of Messages to the outbox. /// - /// The Id of the batch to be flushed + /// The ID of the batch to be flushed /// /// The context of the request; if null we will start one via a /// diff --git a/src/Paramore.Brighter/Observability/BrighterSemanticConventions.cs b/src/Paramore.Brighter/Observability/BrighterSemanticConventions.cs index 3f2f67778e..306e41d2e6 100644 --- a/src/Paramore.Brighter/Observability/BrighterSemanticConventions.cs +++ b/src/Paramore.Brighter/Observability/BrighterSemanticConventions.cs @@ -29,6 +29,7 @@ namespace Paramore.Brighter.Observability; /// public static class BrighterSemanticConventions { + public const string ArchiveAge = "paramore.brighter.archive_age_in_milliseconds"; public const string ArchiveMessages = "paramore.brighter.archive_messages"; public const string CeSource = "cloudevents.event_source"; public const string CeMessageId = "cloudevents.event_id"; diff --git a/src/Paramore.Brighter/Observability/BrighterTracer.cs b/src/Paramore.Brighter/Observability/BrighterTracer.cs index 26b7b9ee0a..2c493cf30a 100644 --- a/src/Paramore.Brighter/Observability/BrighterTracer.cs +++ b/src/Paramore.Brighter/Observability/BrighterTracer.cs @@ -63,7 +63,7 @@ public BrighterTracer(TimeProvider? timeProvider = null) /// public void Dispose() { - ActivitySource?.Dispose(); + ActivitySource.Dispose(); } /// @@ -285,30 +285,40 @@ public void Dispose() return activity; } - + /// /// Creates a span for an archive operation. Because a sweeper may not create an externa bus, but just use the archiver directly, we /// check for this existing and then recreate directly in the archive provider if it does not exist /// /// A parent activity that called this one + /// The minimum age of a row to be archived /// The for how deep should the instrumentation go? /// public Activity? CreateArchiveSpan( Activity? parentActivity, + TimeSpan dispatchedSince, InstrumentationOptions options = InstrumentationOptions.All) { - var spanName = $"{BrighterSemanticConventions.ArchiveMessages} {CommandProcessorSpanOperation.Archive.ToSpanName()}"; + var operation = CommandProcessorSpanOperation.Archive; + var spanName = $"{BrighterSemanticConventions.ArchiveMessages} {operation.ToSpanName()}"; var kind = ActivityKind.Producer; var parentId = parentActivity?.Id; var now = _timeProvider.GetUtcNow(); + var tags = new ActivityTagsCollection() + + { + { BrighterSemanticConventions.Operation, operation.ToSpanName() }, + { BrighterSemanticConventions.ArchiveAge, dispatchedSince.TotalMilliseconds } + }; var activity = ActivitySource.StartActivity( name: spanName, kind: kind, parentId: parentId, + tags: tags, startTime: now); - Activity.Current = activity; + Activity.Current = activity; return activity; } @@ -566,7 +576,6 @@ InstrumentationOptions instrumentationOptions /// /// Create an event representing the external service bus calling the outbox /// This is generic and not specific details from a particular outbox and is thus mostly message properties - /// This is a batch version of /// NOTE: Events are static, as we only need the instance state to create an activity /// /// What are we performing on the group of messages diff --git a/src/Paramore.Brighter/Observability/IAmABrighterTracer.cs b/src/Paramore.Brighter/Observability/IAmABrighterTracer.cs index 3877298a90..58119aaeed 100644 --- a/src/Paramore.Brighter/Observability/IAmABrighterTracer.cs +++ b/src/Paramore.Brighter/Observability/IAmABrighterTracer.cs @@ -25,7 +25,6 @@ THE SOFTWARE. */ using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Diagnostics; namespace Paramore.Brighter.Observability; @@ -74,15 +73,18 @@ public interface IAmABrighterTracer : IDisposable /// check for this existing and then recreate directly in the archive provider if it does not exist /// /// A parent activity that called this one + /// The minimum age of a row to be archived /// The for how deep should the instrumentation go? /// - Activity? CreateArchiveSpan(Activity? parentActivity, InstrumentationOptions options = InstrumentationOptions.All); + Activity? CreateArchiveSpan( + Activity? parentActivity, + TimeSpan dispatchedSince, + InstrumentationOptions options = InstrumentationOptions.All + ); /// /// Create a span for a request in CommandProcessor /// - /// What type of span are we creating - /// What is the request that we are tracking with this span /// The parent activity, if any, that we should assign to this span /// Are there links to other spans that we should add to this span /// How deep should the instrumentation go? @@ -96,12 +98,11 @@ public interface IAmABrighterTracer : IDisposable /// /// The parent span for the message pump. This is the entry point for the message pump /// - /// The . This should be Begin or End + /// The . This should be Begin or End /// The for this span /// The that we are receiving from /// The for how deep should the instrumentation go? /// A span (or dotnet Activity) for the current request named request.name operation.name - /// How deep should the instrumentation go? Activity? CreateMessagePumpSpan( MessagePumpSpanOperation operation, RoutingKey topic, diff --git a/src/Paramore.Brighter/OutboxArchiver.cs b/src/Paramore.Brighter/OutboxArchiver.cs index 05c7d30aef..432fc4d65b 100644 --- a/src/Paramore.Brighter/OutboxArchiver.cs +++ b/src/Paramore.Brighter/OutboxArchiver.cs @@ -55,27 +55,11 @@ public class OutboxArchiver( /// that these are transient errors which can be retried /// /// How stale is the message that we want archive - public void Archive(TimeSpan dispatchedSince) + /// The context for the request pipeline; gives us the OTel span for example + public void Archive(TimeSpan dispatchedSince, RequestContext? requestContext = null) { -#pragma warning disable CS0618 // Type or member is obsolete - var activity = ApplicationTelemetry.ActivitySource.StartActivity(ARCHIVE_OUTBOX, ActivityKind.Server); -#pragma warning restore CS0618 // Type or member is obsolete - var requestContext = _requestContextFactory.Create(); - requestContext.Span = activity; - - try - { - bus.Archive(dispatchedSince, requestContext); - } - catch (Exception e) - { - activity?.SetStatus(ActivityStatusCode.Error, e.Message); - } - finally - { - if(activity?.DisplayName == ARCHIVE_OUTBOX) - activity.Dispose(); - } + requestContext = requestContext ?? _requestContextFactory.Create(); + bus.Archive(dispatchedSince, requestContext); } /// @@ -86,26 +70,10 @@ public void Archive(TimeSpan dispatchedSince) /// How stale is the message that /// The context for the request pipeline; gives us the OTel span for example /// The Cancellation Token - public async Task ArchiveAsync(TimeSpan dispatchedSince, RequestContext requestContext, CancellationToken cancellationToken) + public async Task ArchiveAsync(TimeSpan dispatchedSince, RequestContext? requestContext = null, CancellationToken cancellationToken = default) { -#pragma warning disable CS0618 // Type or member is obsolete - var activity = ApplicationTelemetry.ActivitySource.StartActivity(ARCHIVE_OUTBOX, ActivityKind.Server); -#pragma warning restore CS0618 // Type or member is obsolete - requestContext.Span = activity; - - try - { - await bus.ArchiveAsync(dispatchedSince, requestContext, cancellationToken); - } - catch (Exception e) - { - activity?.SetStatus(ActivityStatusCode.Error, e.Message); - } - finally - { - if(activity?.DisplayName == ARCHIVE_OUTBOX) - activity.Dispose(); - } + requestContext = requestContext ?? _requestContextFactory.Create(); + await bus.ArchiveAsync(dispatchedSince, requestContext, cancellationToken); } } } diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs index 4f8c0178a5..b57bceed5e 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs @@ -25,6 +25,7 @@ public class ExternalServiceBusArchiveObservabilityTests private RoutingKey _routingKey = new("MyEvent"); private readonly InMemoryOutbox _outbox; private readonly TracerProvider _traceProvider; + private const double TOLERANCE = 0.000000001; public ExternalServiceBusArchiveObservabilityTests() { @@ -105,7 +106,8 @@ public void When_archiving_from_the_outbox() _timeProvider.Advance(TimeSpan.FromSeconds(300)); //archive - _bus.Archive(TimeSpan.FromSeconds(100), context); + var dispatchedSince = TimeSpan.FromSeconds(100); + _bus.Archive(dispatchedSince, context); //should be no messages in the outbox _outbox.EntryCount.Should().Be(0); @@ -115,14 +117,28 @@ public void When_archiving_from_the_outbox() _traceProvider.ForceFlush(); //We should have exported matching activities - _exportedActivities.Count.Should().Be(6); + _exportedActivities.Count.Should().Be(9); _exportedActivities.Any(a => a.Source.Name == "Paramore.Brighter").Should().BeTrue(); - //there should be a create span for the batch + //there should be a n archive create span for the batch var createActivity = _exportedActivities.Single(a => a.DisplayName == $"{BrighterSemanticConventions.ArchiveMessages} {CommandProcessorSpanOperation.Archive.ToSpanName()}"); createActivity.Should().NotBeNull(); createActivity.ParentId.Should().Be(parentActivity?.Id); + //check for outstanding messages span + var osCheckActivity = _exportedActivities.SingleOrDefault(a => + a.DisplayName == $"{OutboxDbOperation.DispatchedMessages.ToSpanName()} {InMemoryAttributes.DbName} {InMemoryAttributes.DbTable}"); + osCheckActivity.Should().NotBeNull(); + osCheckActivity.ParentId.Should().Be(createActivity.Id); + + //check for delete messages span + var deleteActivity = _exportedActivities.SingleOrDefault(a => + a.DisplayName == $"{OutboxDbOperation.Delete.ToSpanName()} {InMemoryAttributes.DbName} {InMemoryAttributes.DbTable}"); + deleteActivity.Should().NotBeNull(); + deleteActivity.ParentId.Should().Be(createActivity.Id); + + //check the tags for the create span + createActivity.TagObjects.Should().Contain(t => t.Key == BrighterSemanticConventions.ArchiveAge && Math.Abs(Convert.ToDouble(t.Value) - dispatchedSince.TotalMilliseconds) < TOLERANCE); } } From a72b3529a7fe8c19878af2c3d568e18461482c6d Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Sun, 27 Oct 2024 15:03:06 +0000 Subject: [PATCH 07/15] feat: opentelemetry for the archive operation --- .../Archive/When_archiving_from_the_outbox.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs index b57bceed5e..70ae8ad58d 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs @@ -130,7 +130,7 @@ public void When_archiving_from_the_outbox() var osCheckActivity = _exportedActivities.SingleOrDefault(a => a.DisplayName == $"{OutboxDbOperation.DispatchedMessages.ToSpanName()} {InMemoryAttributes.DbName} {InMemoryAttributes.DbTable}"); osCheckActivity.Should().NotBeNull(); - osCheckActivity.ParentId.Should().Be(createActivity.Id); + osCheckActivity?.ParentId.Should().Be(createActivity.Id); //check for delete messages span var deleteActivity = _exportedActivities.SingleOrDefault(a => @@ -140,5 +140,18 @@ public void When_archiving_from_the_outbox() //check the tags for the create span createActivity.TagObjects.Should().Contain(t => t.Key == BrighterSemanticConventions.ArchiveAge && Math.Abs(Convert.ToDouble(t.Value) - dispatchedSince.TotalMilliseconds) < TOLERANCE); + + //check the tags for the outstanding messages span + osCheckActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbOperation && t.Value == OutboxDbOperation.DispatchedMessages.ToSpanName()).Should().BeTrue(); + osCheckActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbTable && t.Value == InMemoryAttributes.DbTable).Should().BeTrue(); + osCheckActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbSystem && t.Value == DbSystem.Brighter.ToDbName()).Should().BeTrue(); + osCheckActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbName && t.Value == InMemoryAttributes.DbName).Should().BeTrue(); + + //check the tages for the delete messages span + deleteActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbOperation && t.Value == OutboxDbOperation.Delete.ToSpanName()).Should().BeTrue(); + deleteActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbTable && t.Value == InMemoryAttributes.DbTable).Should().BeTrue(); + deleteActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbSystem && t.Value == DbSystem.Brighter.ToDbName()).Should().BeTrue(); + deleteActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbName && t.Value == InMemoryAttributes.DbName).Should().BeTrue(); + } } From 9ddedf756e4efad07ef153d304a6858806472022 Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Sun, 27 Oct 2024 17:01:20 +0000 Subject: [PATCH 08/15] feat: add async archive operation opentelemetry --- ...ring_A_Message_A_Span_Is_Exported_Async.cs | 80 ++++++++++--------- ...ipile_Messages_Spans_Are_Exported_Async.cs | 2 +- ...ng_Multiple_Messages_Spans_Are_Exported.cs | 2 +- 3 files changed, 46 insertions(+), 38 deletions(-) diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported_Async.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported_Async.cs index af5f758fd4..8cd6011db6 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported_Async.cs @@ -121,7 +121,7 @@ public async Task When_Clearing_A_Message_A_Span_Is_Exported() _traceProvider.ForceFlush(); //assert - _exportedActivities.Count.Should().Be(7); + _exportedActivities.Count.Should().Be(8); _exportedActivities.Any(a => a.Source.Name == "Paramore.Brighter").Should().BeTrue(); //there should be a create span for the batch @@ -143,14 +143,14 @@ public async Task When_Clearing_A_Message_A_Span_Is_Exported() var message = _internalBus.Stream(new RoutingKey(_topic)).Single(); var depositEvent = events.Single(e => e.Name == OutboxDbOperation.Get.ToSpanName()); depositEvent.Tags.Any(a => a.Value != null && a.Key == BrighterSemanticConventions.OutboxSharedTransaction && (bool)a.Value == false).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.OutboxType && (string)a.Value == "async" ).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageId && (string)a.Value == message.Id ).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessagingDestination && (RoutingKey)a.Value == message.Header.Topic).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.OutboxType && a.Value as string == "async" ).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageId && a.Value as string == message.Id ).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessagingDestination && a.Value?.ToString() == message.Header.Topic.ToString()).Should().BeTrue(); depositEvent.Tags.Any(a => a is { Value: not null, Key: BrighterSemanticConventions.MessageBodySize } && (int)a.Value == message.Body.Bytes.Length).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageBody && (string)a.Value == message.Body.Value).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageType && (string)a.Value == message.Header.MessageType.ToString()).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessagingDestinationPartitionId && (string)a.Value == message.Header.PartitionKey).Should().BeTrue(); - depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageHeaders && (string)a.Value == JsonSerializer.Serialize(message.Header)).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageBody && a.Value as string == message.Body.Value).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageType && a.Value as string == message.Header.MessageType.ToString()).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessagingDestinationPartitionId && a.Value as string == message.Header.PartitionKey).Should().BeTrue(); + depositEvent.Tags.Any(a => a.Key == BrighterSemanticConventions.MessageHeaders && a.Value as string == JsonSerializer.Serialize(message.Header)).Should().BeTrue(); //there should be a span in the Db for retrieving the message var outBoxActivity = _exportedActivities.Single(a => a.DisplayName == $"{OutboxDbOperation.Get.ToSpanName()} {InMemoryAttributes.DbName} {InMemoryAttributes.DbTable}"); @@ -164,39 +164,47 @@ public async Task When_Clearing_A_Message_A_Span_Is_Exported() producerActivity.ParentId.Should().Be(clearActivity.Id); producerActivity.Kind.Should().Be(ActivityKind.Producer); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessagingOperationType && (string)t.Value == CommandProcessorSpanOperation.Publish.ToSpanName()).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageId && (string)t.Value == message.Id).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageType && (string)t.Value == message.Header.MessageType.ToString()).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t is { Value: not null, Key: BrighterSemanticConventions.MessagingDestination } && t.Value.ToString() == _topic).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessagingDestinationPartitionId && (string)t.Value == message.Header.PartitionKey).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageHeaders && (string)t.Value == JsonSerializer.Serialize(message.Header)).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessagingOperationType && t.Value as string == CommandProcessorSpanOperation.Publish.ToSpanName()).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageId && t.Value as string == message.Id).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageType && t.Value as string == message.Header.MessageType.ToString()).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t is { Value: not null, Key: BrighterSemanticConventions.MessagingDestination } && t.Value.ToString() == _topic.Value.ToString()).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessagingDestinationPartitionId && t.Value as string == message.Header.PartitionKey).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageHeaders && t.Value as string == JsonSerializer.Serialize(message.Header)).Should().BeTrue(); producerActivity.TagObjects.Any(t => t is { Value: not null, Key: BrighterSemanticConventions.MessageBodySize } && (int)t.Value == message.Body.Bytes.Length).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageBody && (string)t.Value == message.Body.Value).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.ConversationId && (string)t.Value == message.Header.CorrelationId).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.MessageBody && t.Value as string == message.Body.Value).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.ConversationId && t.Value as string == message.Header.CorrelationId).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.CeMessageId && (string)t.Value == message.Id).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.CeSource && (Uri)t.Value == _producer.Publication.Source).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.CeVersion && (string)t.Value == "1.0").Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.CeSubject && (string)t.Value == _producer.Publication.Subject).Should().BeTrue(); - producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.CeType && (string)t.Value == _producer.Publication.Type).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.CeMessageId && t.Value as string == message.Id).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.CeSource && t.Value as Uri == _producer.Publication.Source).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.CeVersion && t.Value as string == "1.0").Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.CeSubject && t.Value as string == _producer.Publication.Subject).Should().BeTrue(); + producerActivity.TagObjects.Any(t => t.Key == BrighterSemanticConventions.CeType && t.Value as string == _producer.Publication.Type).Should().BeTrue(); //there should be an event in the producer for producing the message var produceEvent = producerActivity.Events.Single(e => e.Name ==$"{_topic} {CommandProcessorSpanOperation.Publish.ToSpanName()}"); - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessagingOperationType && (string)t.Value == CommandProcessorSpanOperation.Publish.ToSpanName()).Should().BeTrue(); - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessagingSystem && (string)t.Value == MessagingSystem.InternalBus.ToMessagingSystemName()).Should().BeTrue(); - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessagingDestination && (RoutingKey)t.Value == _topic).Should().BeTrue(); - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessagingDestinationPartitionId && (string)t.Value == message.Header.PartitionKey).Should().BeTrue(); - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessageId && (string)t.Value == message.Id).Should().BeTrue(); - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessageType && (string)t.Value == message.Header.MessageType.ToString()).Should().BeTrue(); - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessageHeaders && (string)t.Value == JsonSerializer.Serialize(message.Header)).Should().BeTrue(); + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessagingOperationType && t.Value as string == CommandProcessorSpanOperation.Publish.ToSpanName()).Should().BeTrue(); + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessagingSystem && t.Value as string == MessagingSystem.InternalBus.ToMessagingSystemName()).Should().BeTrue(); + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessagingDestination && t.Value?.ToString() == _topic.Value.ToString()).Should().BeTrue(); + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessagingDestinationPartitionId && t.Value as string == message.Header.PartitionKey).Should().BeTrue(); + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessageId && t.Value as string == message.Id).Should().BeTrue(); + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessageType && t.Value as string == message.Header.MessageType.ToString()).Should().BeTrue(); + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessageHeaders && t.Value as string == JsonSerializer.Serialize(message.Header)).Should().BeTrue(); produceEvent.Tags.Any(t => t is { Value: not null, Key: BrighterSemanticConventions.MessageBodySize } && (int)t.Value == message.Body.Bytes.Length).Should().BeTrue(); - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessageBody && (string)t.Value == message.Body.Value).Should().BeTrue(); - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.ConversationId && (string)t.Value == message.Header.CorrelationId).Should().BeTrue(); - - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.CeMessageId && (string)t.Value == message.Id).Should().BeTrue(); - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.CeSource && (Uri)t.Value == _producer.Publication.Source).Should().BeTrue(); - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.CeVersion && (string)t.Value == "1.0").Should().BeTrue(); - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.CeSubject && (string)t.Value == _producer.Publication.Subject).Should().BeTrue(); - produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.CeType && (string)t.Value == _producer.Publication.Type).Should().BeTrue(); + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.MessageBody && t.Value as string == message.Body.Value).Should().BeTrue(); + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.ConversationId && t.Value as string == message.Header.CorrelationId).Should().BeTrue(); + + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.CeMessageId && t.Value as string == message.Id).Should().BeTrue(); + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.CeSource && t.Value as Uri == _producer.Publication.Source).Should().BeTrue(); + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.CeVersion && t.Value as string == "1.0").Should().BeTrue(); + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.CeSubject && t.Value as string == _producer.Publication.Subject).Should().BeTrue(); + produceEvent.Tags.Any(t => t.Key == BrighterSemanticConventions.CeType && t.Value as string == _producer.Publication.Type).Should().BeTrue(); + + //There should be a span event to mark as dispatched + var markAsDispatchedActivity = _exportedActivities.Single(a => a.DisplayName == $"{OutboxDbOperation.MarkDispatched.ToSpanName()} {InMemoryAttributes.DbName} {InMemoryAttributes.DbTable}"); + markAsDispatchedActivity.Tags.Any(t => t.Key == BrighterSemanticConventions.DbOperation && t.Value == OutboxDbOperation.MarkDispatched.ToSpanName()).Should().BeTrue(); + markAsDispatchedActivity.Tags.Any(t => t.Key == BrighterSemanticConventions.DbTable && t.Value == InMemoryAttributes.DbTable).Should().BeTrue(); + markAsDispatchedActivity.Tags.Any(t => t.Key == BrighterSemanticConventions.DbSystem && t.Value == DbSystem.Brighter.ToDbName()).Should().BeTrue(); + markAsDispatchedActivity.Tags.Any(t => t.Key == BrighterSemanticConventions.DbName && t.Value == InMemoryAttributes.DbName).Should().BeTrue(); + } } diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multipile_Messages_Spans_Are_Exported_Async.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multipile_Messages_Spans_Are_Exported_Async.cs index fcc33ca41a..3109255448 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multipile_Messages_Spans_Are_Exported_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multipile_Messages_Spans_Are_Exported_Async.cs @@ -126,7 +126,7 @@ public async Task When_Clearing_A_Message_A_Span_Is_Exported() _traceProvider.ForceFlush(); //assert - _exportedActivities.Count.Should().Be(18); + _exportedActivities.Count.Should().Be(21); _exportedActivities.Any(a => a.Source.Name == "Paramore.Brighter").Should().BeTrue(); //there should be a create span for the batch diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multiple_Messages_Spans_Are_Exported.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multiple_Messages_Spans_Are_Exported.cs index d9d0c94d93..da62fac280 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multiple_Messages_Spans_Are_Exported.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multiple_Messages_Spans_Are_Exported.cs @@ -125,7 +125,7 @@ public void When_Clearing_A_Message_A_Span_Is_Exported() _traceProvider.ForceFlush(); //assert - _exportedActivities.Count.Should().Be(18); + _exportedActivities.Count.Should().Be(21); _exportedActivities.Any(a => a.Source.Name == "Paramore.Brighter").Should().BeTrue(); //there should be a create span for the batch From 5a60cc82c3588ad518f3a5ea7188dbe27c19134a Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Sun, 27 Oct 2024 17:25:20 +0000 Subject: [PATCH 09/15] feat: cleanup old archiver telemetry --- src/Paramore.Brighter/OutboxArchiver.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/Paramore.Brighter/OutboxArchiver.cs b/src/Paramore.Brighter/OutboxArchiver.cs index 432fc4d65b..8e50f7a182 100644 --- a/src/Paramore.Brighter/OutboxArchiver.cs +++ b/src/Paramore.Brighter/OutboxArchiver.cs @@ -23,12 +23,8 @@ THE SOFTWARE. */ #endregion using System; -using System.Diagnostics; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Paramore.Brighter.Logging; namespace Paramore.Brighter { @@ -42,13 +38,8 @@ public class OutboxArchiver( IAmARequestContextFactory? requestContextFactory = null) where TMessage : Message { - private const string ARCHIVE_OUTBOX = "Archive Outbox"; - - private readonly ILogger _logger = ApplicationLogging.CreateLogger>(); private readonly IAmARequestContextFactory _requestContextFactory = requestContextFactory ?? new InMemoryRequestContextFactory(); - private const string SUCCESS_MESSAGE = "Successfully archiver {NumberOfMessageArchived} out of {MessagesToArchive}, batch size : {BatchSize}"; - /// /// Archive Message from the outbox to the outbox archive provider /// Outbox Archiver will swallow any errors during the archive process, but record them. Assumption is @@ -58,7 +49,7 @@ public class OutboxArchiver( /// The context for the request pipeline; gives us the OTel span for example public void Archive(TimeSpan dispatchedSince, RequestContext? requestContext = null) { - requestContext = requestContext ?? _requestContextFactory.Create(); + requestContext ??= _requestContextFactory.Create(); bus.Archive(dispatchedSince, requestContext); } @@ -72,7 +63,7 @@ public void Archive(TimeSpan dispatchedSince, RequestContext? requestContext = n /// The Cancellation Token public async Task ArchiveAsync(TimeSpan dispatchedSince, RequestContext? requestContext = null, CancellationToken cancellationToken = default) { - requestContext = requestContext ?? _requestContextFactory.Create(); + requestContext ??= _requestContextFactory.Create(); await bus.ArchiveAsync(dispatchedSince, requestContext, cancellationToken); } } From 4de9e22d1bc4bec144e0b2f687d8f8992638ce53 Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Sun, 27 Oct 2024 22:53:36 +0000 Subject: [PATCH 10/15] feat: add archive async telemetry --- src/Paramore.Brighter/CommandProcessor.cs | 53 +++++- src/Paramore.Brighter/ExternalBusService.cs | 25 ++- .../MessageMapperRegistry.cs | 8 +- .../Observability/BrighterTracer.cs | 25 +++ .../Observability/IAmABrighterTracer.cs | 8 + .../When_archiving_from_the_outbox_async.cs | 159 ++++++++++++++++++ 6 files changed, 261 insertions(+), 17 deletions(-) create mode 100644 tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox_async.cs diff --git a/src/Paramore.Brighter/CommandProcessor.cs b/src/Paramore.Brighter/CommandProcessor.cs index b0909e8dac..e900a4cf68 100644 --- a/src/Paramore.Brighter/CommandProcessor.cs +++ b/src/Paramore.Brighter/CommandProcessor.cs @@ -247,9 +247,9 @@ public void Send(T command, RequestContext? requestContext = null) where T : handlerChain.First().Handle(command); } - catch (Exception) + catch (Exception e) { - span?.SetStatus(ActivityStatusCode.Error); + _tracer?.AddExceptionToSpan(span, [e]); throw; } finally @@ -296,9 +296,9 @@ public async Task SendAsync( await handlerChain.First().HandleAsync(command, cancellationToken) .ConfigureAwait(continueOnCapturedContext); } - catch (Exception) + catch (Exception e) { - span?.SetStatus(ActivityStatusCode.Error); + _tracer?.AddExceptionToSpan(span, [e]); throw; } finally @@ -362,7 +362,7 @@ public void Publish(T @event, RequestContext? requestContext = null) where T if (exceptions.Any()) { - span?.SetStatus(ActivityStatusCode.Error); + _tracer?.AddExceptionToSpan(span, exceptions); throw new AggregateException( "Failed to publish to one more handlers successfully, see inner exceptions for details", exceptions); @@ -441,7 +441,7 @@ public async Task PublishAsync( _tracer?.LinkSpans(handlerSpans); if (exceptions.Any()) - span?.SetStatus(ActivityStatusCode.Error); + _tracer?.AddExceptionToSpan(span, exceptions); if (exceptions.Count > 0) { @@ -573,6 +573,11 @@ public string DepositPost( return message.Id!; } + catch (Exception e) + { + _tracer?.AddExceptionToSpan(span, [e]); + throw; + } finally { _tracer?.EndSpan(span); @@ -643,6 +648,11 @@ public string[] DepositPost( return successfullySentMessage.ToArray(); } + catch (Exception e) + { + _tracer?.AddExceptionToSpan(span, [e]); + throw; + } finally { _tracer?.EndSpan(span); @@ -760,6 +770,11 @@ await bus.AddToOutboxAsync(message, context, transactionProvider, continueOnCapt return message.Id!; } + catch (Exception e) + { + _tracer?.AddExceptionToSpan(span, [e]); + throw; + } finally { _tracer?.EndSpan(span); @@ -845,6 +860,11 @@ public async Task DepositPostAsync( return successfullySentMessage.ToArray(); } + catch (Exception e) + { + _tracer?.AddExceptionToSpan(span, [e]); + throw; + } finally { _tracer?.EndSpan(span); @@ -901,6 +921,11 @@ public void ClearOutbox(string[] ids, RequestContext? requestContext = null, Dic { s_bus!.ClearOutbox(ids, context, args); } + catch (Exception e) + { + _tracer?.AddExceptionToSpan(span, [e]); + throw; + } finally { _tracer?.EndSpan(span); @@ -930,6 +955,11 @@ public async Task ClearOutboxAsync( { await s_bus!.ClearOutboxAsync(posts, context, continueOnCapturedContext, args, cancellationToken); } + catch (Exception e) + { + _tracer?.AddExceptionToSpan(span, [e]); + throw; + } finally { _tracer?.EndSpan(span); @@ -962,6 +992,11 @@ public void ClearOutstandingFromOutbox( var minAge = minimumAge ?? TimeSpan.FromMilliseconds(5000); s_bus!.ClearOutstandingFromOutbox(amountToClear, minAge, useBulk, context, args); } + catch (Exception e) + { + _tracer?.AddExceptionToSpan(span, [e]); + throw; + } finally { _tracer?.EndSpan(span); @@ -1042,11 +1077,15 @@ public void ClearOutstandingFromOutbox( return response; } - s_logger.LogInformation("Deleting queue for routingkey: {ChannelName}", channelName); return null; } + catch (Exception e) + { + _tracer?.AddExceptionToSpan(span, [e]); + throw; + } finally { _tracer?.EndSpan(span); diff --git a/src/Paramore.Brighter/ExternalBusService.cs b/src/Paramore.Brighter/ExternalBusService.cs index 6350519c78..9755631817 100644 --- a/src/Paramore.Brighter/ExternalBusService.cs +++ b/src/Paramore.Brighter/ExternalBusService.cs @@ -254,8 +254,8 @@ public void Archive(TimeSpan dispatchedSince, RequestContext requestContext) { //This is an archive span parent; we expect individual archiving operations for messages to have their own spans var parentSpan = requestContext.Span; - var createSpan = _tracer.CreateArchiveSpan(requestContext.Span, dispatchedSince, options: _instrumentationOptions); - requestContext.Span = createSpan; + var span = _tracer.CreateArchiveSpan(requestContext.Span, dispatchedSince, options: _instrumentationOptions); + requestContext.Span = span; try { @@ -288,11 +288,12 @@ public void Archive(TimeSpan dispatchedSince, RequestContext requestContext) catch (Exception e) { s_logger.LogError(e, "Error while archiving from the outbox"); + _tracer?.AddExceptionToSpan(span, [e]); throw; } finally { - _tracer.EndSpan(createSpan); + _tracer?.EndSpan(span); requestContext.Span = parentSpan; } } @@ -304,9 +305,17 @@ public void Archive(TimeSpan dispatchedSince, RequestContext requestContext) /// /// /// The Cancellation Token - public async Task ArchiveAsync(TimeSpan dispatchedSince, RequestContext requestContext, - CancellationToken cancellationToken) + public async Task ArchiveAsync( + TimeSpan dispatchedSince, + RequestContext requestContext, + CancellationToken cancellationToken = default + ) { + //This is an archive span parent; we expect individual archiving operations for messages to have their own spans + var parentSpan = requestContext.Span; + var span = _tracer.CreateArchiveSpan(requestContext.Span, dispatchedSince, options: _instrumentationOptions); + requestContext.Span = span; + try { if (_asyncOutbox is null) throw new ArgumentException(NoAsyncOutboxError); @@ -330,8 +339,14 @@ await _asyncOutbox.DeleteAsync(messages.Select(e => e.Id).ToArray(), requestCont catch (Exception e) { s_logger.LogError(e, "Error while archiving from the outbox"); + _tracer?.AddExceptionToSpan(span, [e]); throw; } + finally + { + _tracer?.EndSpan(span); + requestContext.Span = parentSpan; + } } /// diff --git a/src/Paramore.Brighter/MessageMapperRegistry.cs b/src/Paramore.Brighter/MessageMapperRegistry.cs index 8fe0dd3189..6e1ad7d3dc 100644 --- a/src/Paramore.Brighter/MessageMapperRegistry.cs +++ b/src/Paramore.Brighter/MessageMapperRegistry.cs @@ -23,9 +23,7 @@ THE SOFTWARE. */ #endregion using System; -using System.Collections; using System.Collections.Generic; -using System.Linq; namespace Paramore.Brighter { @@ -38,7 +36,7 @@ namespace Paramore.Brighter /// public class MessageMapperRegistry : IAmAMessageMapperRegistry, IAmAMessageMapperRegistryAsync { - private readonly IAmAMessageMapperFactory _messageMapperFactory; + private readonly IAmAMessageMapperFactory? _messageMapperFactory; private readonly IAmAMessageMapperFactoryAsync? _messageMapperFactoryAsync; private readonly Dictionary _messageMappers = new Dictionary(); private readonly Dictionary _asyncMessageMappers = new Dictionary(); @@ -48,7 +46,7 @@ public class MessageMapperRegistry : IAmAMessageMapperRegistry, IAmAMessageMappe /// /// The message mapper factory. /// The async message mapper factory - public MessageMapperRegistry(IAmAMessageMapperFactory messageMapperFactory, IAmAMessageMapperFactoryAsync? messageMapperFactoryAsync) + public MessageMapperRegistry(IAmAMessageMapperFactory? messageMapperFactory, IAmAMessageMapperFactoryAsync? messageMapperFactoryAsync) { _messageMapperFactory = messageMapperFactory; _messageMapperFactoryAsync = messageMapperFactoryAsync; @@ -64,7 +62,7 @@ public MessageMapperRegistry(IAmAMessageMapperFactory messageMapperFactory, IAmA /// IAmAMessageMapper<TRequest>. public IAmAMessageMapper? Get() where TRequest : class, IRequest { - if (_messageMappers.ContainsKey(typeof(TRequest))) + if ( _messageMapperFactory is not null && _messageMappers.ContainsKey(typeof(TRequest))) { var messageMapperType = _messageMappers[typeof(TRequest)]; return (IAmAMessageMapper)_messageMapperFactory.Create(messageMapperType); diff --git a/src/Paramore.Brighter/Observability/BrighterTracer.cs b/src/Paramore.Brighter/Observability/BrighterTracer.cs index 2c493cf30a..d1f20e7f62 100644 --- a/src/Paramore.Brighter/Observability/BrighterTracer.cs +++ b/src/Paramore.Brighter/Observability/BrighterTracer.cs @@ -66,6 +66,31 @@ public void Dispose() ActivitySource.Dispose(); } + /// + /// If an activity has an exception, then we should record it on the span + /// + /// + /// + public void AddExceptionToSpan(Activity? span, IEnumerable exceptions) + { + if (span == null ) return; + + var exceptionList = exceptions.ToArray(); + + if (exceptionList.Length == 0) return; + + if (exceptionList .Length == 1) + { + span.RecordException(exceptionList[0]); + span.SetStatus(ActivityStatusCode.Error, exceptionList[0].Message); + return; + } + + var exception = new AggregateException("Operation failed, see inner exceptions for details", exceptionList); + span.RecordException(exception); + span.SetStatus(ActivityStatusCode.Error, exception.Message); + } + /// /// Create a span for a request in CommandProcessor /// diff --git a/src/Paramore.Brighter/Observability/IAmABrighterTracer.cs b/src/Paramore.Brighter/Observability/IAmABrighterTracer.cs index 58119aaeed..2b45bb5e10 100644 --- a/src/Paramore.Brighter/Observability/IAmABrighterTracer.cs +++ b/src/Paramore.Brighter/Observability/IAmABrighterTracer.cs @@ -25,6 +25,7 @@ THE SOFTWARE. */ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Diagnostics; namespace Paramore.Brighter.Observability; @@ -184,4 +185,11 @@ public interface IAmABrighterTracer : IDisposable /// /// void LinkSpans(ConcurrentDictionary handlerSpans); + + /// + /// If an activity has an exception, then we should record it on the span + /// + /// + /// + void AddExceptionToSpan(Activity? span, IEnumerable exceptions); } diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox_async.cs b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox_async.cs new file mode 100644 index 0000000000..aa3cc57638 --- /dev/null +++ b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox_async.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using System.Transactions; +using FluentAssertions; +using Microsoft.Extensions.Time.Testing; +using OpenTelemetry; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; +using Paramore.Brighter.Core.Tests.CommandProcessors.TestDoubles; +using Paramore.Brighter.Observability; +using Polly; +using Polly.Registry; +using Xunit; +// ReSharper disable ExplicitCallerInfoArgument + +namespace Paramore.Brighter.Core.Tests.Observability.Archive; + +public class AsyncExternalServiceBusArchiveObservabilityTests +{ + private readonly List _exportedActivities = new(); + private readonly ExternalBusService _bus; + private readonly Publication _publication; + private readonly FakeTimeProvider _timeProvider; + private RoutingKey _routingKey = new("MyEvent"); + private readonly InMemoryOutbox _outbox; + private readonly TracerProvider _traceProvider; + private const double TOLERANCE = 0.000000001; + + public AsyncExternalServiceBusArchiveObservabilityTests() + { + IAmABus internalBus = new InternalBus(); + _timeProvider = new FakeTimeProvider(); + var tracer = new BrighterTracer(_timeProvider); + + var builder = Sdk.CreateTracerProviderBuilder(); + + _traceProvider = builder + .AddSource("Paramore.Brighter.Tests", "Paramore.Brighter") + .ConfigureResource(r => r.AddService("in-memory-tracer")) + .AddInMemoryExporter(_exportedActivities) + .Build(); + + Brighter.CommandProcessor.ClearServiceBus(); + + _publication = new Publication + { + Source = new Uri("http://localhost"), + RequestType = typeof(MyEvent), + Topic = _routingKey, + Type = nameof(MyEvent), + }; + + var producer = new InMemoryProducer(internalBus, _timeProvider) + { + Publication = _publication + }; + + var producerRegistry = + new ProducerRegistry(new Dictionary { { _routingKey, producer } }); + + var retryPolicy = Policy + .Handle() + .RetryAsync(); + + var policyRegistry = new PolicyRegistry { { Brighter.CommandProcessor.RETRYPOLICYASYNC, retryPolicy } }; + + var messageMapperRegistry = new MessageMapperRegistry( + new SimpleMessageMapperFactory((_) => new MyEventMessageMapper()), + null); + messageMapperRegistry.Register(); + + _outbox = new InMemoryOutbox(_timeProvider) { Tracer = tracer }; + var archiveProvider = new InMemoryArchiveProvider(); + + _bus = new ExternalBusService( + producerRegistry, + policyRegistry, + messageMapperRegistry, + new EmptyMessageTransformerFactory(), + new EmptyMessageTransformerFactoryAsync(), + tracer, + _outbox, + archiveProvider, + timeProvider:_timeProvider); + } + + [Fact] + public async Task When_archiving_from_the_outbox() + { + var parentActivity = new ActivitySource("Paramore.Brighter.Tests").StartActivity("BrighterTracerSpanTests"); + + var context = new RequestContext(); + context.Span = parentActivity; + + //add and clear message + var myEvent = new MyEvent(); + var myMessage = new MyEventMessageMapper().MapToMessage(myEvent, _publication); + await _bus.AddToOutboxAsync(myMessage, context); + await _bus.ClearOutboxAsync([myMessage.Id], context); + + //se should have an entry in the outbox + _outbox.EntryCount.Should().Be(1); + + //allow time to pass + _timeProvider.Advance(TimeSpan.FromSeconds(300)); + + //archive + var dispatchedSince = TimeSpan.FromSeconds(100); + await _bus.ArchiveAsync(dispatchedSince, context); + + //should be no messages in the outbox + _outbox.EntryCount.Should().Be(0); + + parentActivity?.Stop(); + + _traceProvider.ForceFlush(); + + //We should have exported matching activities + _exportedActivities.Count.Should().Be(9); + + _exportedActivities.Any(a => a.Source.Name == "Paramore.Brighter").Should().BeTrue(); + + //there should be a n archive create span for the batch + var createActivity = _exportedActivities.Single(a => a.DisplayName == $"{BrighterSemanticConventions.ArchiveMessages} {CommandProcessorSpanOperation.Archive.ToSpanName()}"); + createActivity.Should().NotBeNull(); + createActivity.ParentId.Should().Be(parentActivity?.Id); + + //check for outstanding messages span + var osCheckActivity = _exportedActivities.SingleOrDefault(a => + a.DisplayName == $"{OutboxDbOperation.DispatchedMessages.ToSpanName()} {InMemoryAttributes.DbName} {InMemoryAttributes.DbTable}"); + osCheckActivity.Should().NotBeNull(); + osCheckActivity?.ParentId.Should().Be(createActivity.Id); + + //check for delete messages span + var deleteActivity = _exportedActivities.SingleOrDefault(a => + a.DisplayName == $"{OutboxDbOperation.Delete.ToSpanName()} {InMemoryAttributes.DbName} {InMemoryAttributes.DbTable}"); + deleteActivity.Should().NotBeNull(); + deleteActivity?.ParentId.Should().Be(createActivity.Id); + + //check the tags for the create span + createActivity.TagObjects.Should().Contain(t => t.Key == BrighterSemanticConventions.ArchiveAge && Math.Abs(Convert.ToDouble(t.Value) - dispatchedSince.TotalMilliseconds) < TOLERANCE); + + //check the tags for the outstanding messages span + osCheckActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbOperation && t.Value == OutboxDbOperation.DispatchedMessages.ToSpanName()).Should().BeTrue(); + osCheckActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbTable && t.Value == InMemoryAttributes.DbTable).Should().BeTrue(); + osCheckActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbSystem && t.Value == DbSystem.Brighter.ToDbName()).Should().BeTrue(); + osCheckActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbName && t.Value == InMemoryAttributes.DbName).Should().BeTrue(); + + //check the tages for the delete messages span + deleteActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbOperation && t.Value == OutboxDbOperation.Delete.ToSpanName()).Should().BeTrue(); + deleteActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbTable && t.Value == InMemoryAttributes.DbTable).Should().BeTrue(); + deleteActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbSystem && t.Value == DbSystem.Brighter.ToDbName()).Should().BeTrue(); + deleteActivity?.Tags.Any(t => t.Key == BrighterSemanticConventions.DbName && t.Value == InMemoryAttributes.DbName).Should().BeTrue(); + + } +} From 68d77b98276d966f8850727c8f2efc02c53419fb Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Mon, 28 Oct 2024 09:34:16 +0000 Subject: [PATCH 11/15] feat: move archive functionality to OutboxArchiver.cs --- docs/adr/0021-move-archive-from-esb.md | 32 +++++ .../HostedServiceCollectionExtensions.cs | 2 +- .../TimedOutboxArchiver.cs | 49 ++++--- src/Paramore.Brighter/ExternalBusService.cs | 114 --------------- .../IAmAnExternalBusService.cs | 16 --- src/Paramore.Brighter/OutboxArchiver.cs | 130 +++++++++++++++++- ..._Archiving_Old_Messages_From_The_Outbox.cs | 52 ++----- ...ving_Old_Messages_From_The_Outbox_Async.cs | 56 +------- .../Archive/When_archiving_from_the_outbox.cs | 10 +- .../When_archiving_from_the_outbox_async.cs | 8 +- 10 files changed, 214 insertions(+), 255 deletions(-) create mode 100644 docs/adr/0021-move-archive-from-esb.md diff --git a/docs/adr/0021-move-archive-from-esb.md b/docs/adr/0021-move-archive-from-esb.md new file mode 100644 index 0000000000..235f7e9df0 --- /dev/null +++ b/docs/adr/0021-move-archive-from-esb.md @@ -0,0 +1,32 @@ +# 20. Move Archive Methods from External Service Bus to Outbox Archiver to Reduce Complexity + +Date: 2024-10-28 + +## Status + +Adopted + +## Context + +The `ExternalServiceBus` class is a mediator between producer and outbox. It suffers from complexity, see ADR 0020. + +The `ExternalServiceBus` class has a number of methods that are related to archiving messages. These methods are: + - Archive + - ArchiveAsync + +The OutboxArchiver and the TimedOuboxArchiver are the only callers of these ExternalBus Archive methods. The TimedOutboxArchiver provides both a timer that fires the archiver at a given periodic interval, and uses the global distributed lock to ensure only one archiver runs. + +## Decision + +Whilst the `Archive` methods were not called out by CodeScene analysis, they do add to the overall set of responsibilities of `ExternalServiceBus`. As they have different reasons to change to `ExternalServiceBus` they should be moved to a separate class. + +We will move the implementation from `ExternalServiceBus` into `OutboxArchiver`. We will call `OutboxArchiver` from `TimedOutboxArchiver`. + +## Consequences + +One, we have moved these functions, it makes sense to rename the `ExternalServiceBus` class to 'OutboxProducerMediator' as this better describes its role within our codebase. + + + + + diff --git a/src/Paramore.Brighter.Extensions.Hosting/HostedServiceCollectionExtensions.cs b/src/Paramore.Brighter.Extensions.Hosting/HostedServiceCollectionExtensions.cs index 9ee2232037..6a4bb21473 100644 --- a/src/Paramore.Brighter.Extensions.Hosting/HostedServiceCollectionExtensions.cs +++ b/src/Paramore.Brighter.Extensions.Hosting/HostedServiceCollectionExtensions.cs @@ -57,7 +57,7 @@ public static IBrighterBuilder UseOutboxArchiver(this IBrighterBui brighterBuilder.Services.TryAddSingleton(options); brighterBuilder.Services.AddSingleton(archiveProvider); - brighterBuilder.Services.AddHostedService(); + brighterBuilder.Services.AddHostedService>(); return brighterBuilder; } diff --git a/src/Paramore.Brighter.Extensions.Hosting/TimedOutboxArchiver.cs b/src/Paramore.Brighter.Extensions.Hosting/TimedOutboxArchiver.cs index 713ba27b08..bb2b819110 100644 --- a/src/Paramore.Brighter.Extensions.Hosting/TimedOutboxArchiver.cs +++ b/src/Paramore.Brighter.Extensions.Hosting/TimedOutboxArchiver.cs @@ -25,29 +25,43 @@ THE SOFTWARE. */ using System; using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Paramore.Brighter.Logging; +// ReSharper disable StaticMemberInGenericType namespace Paramore.Brighter.Extensions.Hosting { - /// /// The archiver will find messages in the outbox that are older than a certain age and archive them /// - /// Needed to create a scope within which to create a - /// Used to ensure that only one instance of the is running - /// The that control how the archiver runs, such as interval - public class TimedOutboxArchiver( - IServiceScopeFactory serviceScopeFactory, - IDistributedLock distributedLock, - TimedOutboxArchiverOptions options - ) - : IHostedService, IDisposable + public class TimedOutboxArchiver : IHostedService, IDisposable where TMessage : Message { private static readonly ILogger s_logger = ApplicationLogging.CreateLogger(); private Timer _timer; + private readonly OutboxArchiver _archiver; + private readonly TimeSpan _dispatchedSince; + private readonly IDistributedLock _distributedLock; + private readonly TimedOutboxArchiverOptions _options; + + /// + /// The archiver will find messages in the outbox that are older than a certain age and archive them + /// + /// The archiver to use + /// How old should a message be, in order to archive it? + /// Used to ensure that only one instance of the is running + /// The that control how the archiver runs, such as interval + public TimedOutboxArchiver( + OutboxArchiver archiver, + TimeSpan dispatchedSince, + IDistributedLock distributedLock, + TimedOutboxArchiverOptions options) + { + _archiver = archiver; + _dispatchedSince = dispatchedSince; + _distributedLock = distributedLock; + _options = options; + } private const string LockingResourceName = "Archiver"; @@ -60,8 +74,8 @@ public Task StartAsync(CancellationToken cancellationToken) { s_logger.LogInformation("Outbox Archiver Service is starting"); - _timer = new Timer(async (e) => await Archive(e, cancellationToken), null, TimeSpan.Zero, - TimeSpan.FromSeconds(options.TimerInterval)); + _timer = new Timer(async e => await Archive(e, cancellationToken), null, TimeSpan.Zero, + TimeSpan.FromSeconds(_options.TimerInterval)); return Task.CompletedTask; } @@ -90,16 +104,13 @@ public void Dispose() private async Task Archive(object state, CancellationToken cancellationToken) { - var lockId = await distributedLock.ObtainLockAsync(LockingResourceName, cancellationToken); + var lockId = await _distributedLock.ObtainLockAsync(LockingResourceName, cancellationToken); if (lockId != null) { - var scope = serviceScopeFactory.CreateScope(); s_logger.LogInformation("Outbox Archiver looking for messages to Archive"); try { - IAmAnExternalBusService externalBusService = scope.ServiceProvider.GetService(); - - await externalBusService.ArchiveAsync(options.MinimumAge, new RequestContext(), cancellationToken); + await _archiver.ArchiveAsync(_dispatchedSince, new RequestContext(), cancellationToken); } catch (Exception e) { @@ -107,7 +118,7 @@ private async Task Archive(object state, CancellationToken cancellationToken) } finally { - await distributedLock.ReleaseLockAsync(LockingResourceName, lockId, cancellationToken); + await _distributedLock.ReleaseLockAsync(LockingResourceName, lockId, cancellationToken); } s_logger.LogInformation("Outbox Sweeper sleeping"); diff --git a/src/Paramore.Brighter/ExternalBusService.cs b/src/Paramore.Brighter/ExternalBusService.cs index 9755631817..f9f18c89c7 100644 --- a/src/Paramore.Brighter/ExternalBusService.cs +++ b/src/Paramore.Brighter/ExternalBusService.cs @@ -26,14 +26,12 @@ public class ExternalBusService : IAmAnExternalBusServic private static readonly ILogger s_logger = ApplicationLogging.CreateLogger(); private readonly IPolicyRegistry _policyRegistry; - private readonly IAmAnArchiveProvider? _archiveProvider; private readonly TransformPipelineBuilder _transformPipelineBuilder; private readonly TransformPipelineBuilderAsync _transformPipelineBuilderAsync; private readonly IAmAnOutboxSync? _outBox; private readonly IAmAnOutboxAsync? _asyncOutbox; private readonly int _outboxTimeout; private readonly IAmAProducerRegistry _producerRegistry; - private readonly int _archiveBatchSize; private readonly InstrumentationOptions _instrumentationOptions; private readonly Dictionary> _outboxBatches = new(); @@ -49,7 +47,6 @@ public class ExternalBusService : IAmAnExternalBusServic private const string NoSyncOutboxError = "A sync Outbox must be defined."; private const string NoAsyncOutboxError = "An async Outbox must be defined."; - private const string NoArchiveProviderError = "An Archive Provider must be defined."; //Uses -1 to indicate no outbox and will thus force a throw on a failed publish private int _outStandingCount; @@ -70,13 +67,11 @@ public class ExternalBusService : IAmAnExternalBusServic /// The factory used to create a transformer pipeline for an async message mapper /// /// An outbox for transactional messaging, if none is provided, use an InMemoryOutbox - /// When archiving rows from the Outbox, abstracts to where we should send them /// /// How long to timeout for with an outbox /// How many messages can become outstanding in the Outbox before we throw an OutboxLimitReached exception /// How long before we check for maxOutStandingMessages /// An outbox may require additional arguments, such as a topic list to search - /// What batch size to use when archiving from the Outbox /// /// How verbose do we want our instrumentation to be public ExternalBusService(IAmAProducerRegistry producerRegistry, @@ -86,13 +81,11 @@ public ExternalBusService(IAmAProducerRegistry producerRegistry, IAmAMessageTransformerFactoryAsync messageTransformerFactoryAsync, IAmABrighterTracer tracer, IAmAnOutbox? outbox = null, - IAmAnArchiveProvider? archiveProvider = null, IAmARequestContextFactory? requestContextFactory = null, int outboxTimeout = 300, int maxOutStandingMessages = -1, TimeSpan? maxOutStandingCheckInterval = null, Dictionary? outBoxBag = null, - int archiveBatchSize = 100, TimeProvider? timeProvider = null, InstrumentationOptions instrumentationOptions = InstrumentationOptions.All) { @@ -100,7 +93,6 @@ public ExternalBusService(IAmAProducerRegistry producerRegistry, throw new ConfigurationException("Missing Producer Registry for External Bus Services"); _policyRegistry = policyRegistry ?? throw new ConfigurationException("Missing Policy Registry for External Bus Services"); - _archiveProvider = archiveProvider; requestContextFactory ??= new InMemoryRequestContextFactory(); @@ -132,7 +124,6 @@ public ExternalBusService(IAmAProducerRegistry producerRegistry, _maxOutStandingMessages = maxOutStandingMessages; _maxOutStandingCheckInterval = maxOutStandingCheckInterval ?? TimeSpan.FromMilliseconds(1000); _outBoxBag = outBoxBag ?? new Dictionary(); - _archiveBatchSize = archiveBatchSize; _instrumentationOptions = instrumentationOptions; _tracer = tracer; @@ -244,111 +235,6 @@ public void AddToOutbox( throw new ChannelFailureException($"Could not write message {message.Id} to the outbox"); } - /// - /// Archive Message from the outbox to the outbox archive provider - /// Throws any archiving exception - /// - /// Minimum age - /// The request context for the pipeline - public void Archive(TimeSpan dispatchedSince, RequestContext requestContext) - { - //This is an archive span parent; we expect individual archiving operations for messages to have their own spans - var parentSpan = requestContext.Span; - var span = _tracer.CreateArchiveSpan(requestContext.Span, dispatchedSince, options: _instrumentationOptions); - requestContext.Span = span; - - try - { - if (_outBox is null) throw new ArgumentException(NoSyncOutboxError); - if (_archiveProvider is null) throw new ArgumentException(NoArchiveProviderError); - var messages = _outBox - .DispatchedMessages(dispatchedSince, requestContext, _archiveBatchSize) - .ToArray(); - - s_logger.LogInformation( - "Found {NumberOfMessageArchived} message to archive, batch size : {BatchSize}", - messages.Count(), _archiveBatchSize - ); - - if (messages.Length <= 0) return; - - foreach (var message in messages) - { - _archiveProvider.ArchiveMessage(message); - } - - _outBox.Delete(messages.Select(e => e.Id).ToArray(), requestContext); - - s_logger.LogInformation( - "Successfully archived {NumberOfMessageArchived}, batch size : {BatchSize}", - messages.Count(), - _archiveBatchSize - ); - } - catch (Exception e) - { - s_logger.LogError(e, "Error while archiving from the outbox"); - _tracer?.AddExceptionToSpan(span, [e]); - throw; - } - finally - { - _tracer?.EndSpan(span); - requestContext.Span = parentSpan; - } - } - - /// - /// Archive Message from the outbox to the outbox archive provider - /// Throws any archiving exception - /// - /// - /// - /// The Cancellation Token - public async Task ArchiveAsync( - TimeSpan dispatchedSince, - RequestContext requestContext, - CancellationToken cancellationToken = default - ) - { - //This is an archive span parent; we expect individual archiving operations for messages to have their own spans - var parentSpan = requestContext.Span; - var span = _tracer.CreateArchiveSpan(requestContext.Span, dispatchedSince, options: _instrumentationOptions); - requestContext.Span = span; - - try - { - if (_asyncOutbox is null) throw new ArgumentException(NoAsyncOutboxError); - if (_archiveProvider is null) throw new ArgumentException(NoArchiveProviderError); - var messages = (await _asyncOutbox.DispatchedMessagesAsync( - dispatchedSince, requestContext, pageSize: _archiveBatchSize, - cancellationToken: cancellationToken - )).ToArray(); - - if (messages.Length <= 0) return; - - foreach (var message in messages) - { - await _archiveProvider.ArchiveMessageAsync(message, cancellationToken); - } - - await _asyncOutbox.DeleteAsync(messages.Select(e => e.Id).ToArray(), requestContext, - cancellationToken: cancellationToken - ); - } - catch (Exception e) - { - s_logger.LogError(e, "Error while archiving from the outbox"); - _tracer?.AddExceptionToSpan(span, [e]); - throw; - } - finally - { - _tracer?.EndSpan(span); - requestContext.Span = parentSpan; - } - } - /// /// Used with RPC to call a remote service via the external bus /// diff --git a/src/Paramore.Brighter/IAmAnExternalBusService.cs b/src/Paramore.Brighter/IAmAnExternalBusService.cs index 056ce8c665..f588cf5431 100644 --- a/src/Paramore.Brighter/IAmAnExternalBusService.cs +++ b/src/Paramore.Brighter/IAmAnExternalBusService.cs @@ -11,22 +11,6 @@ namespace Paramore.Brighter /// public interface IAmAnExternalBusService : IDisposable { - - /// - /// Archive Message from the outbox to the outbox archive provider - /// - /// Minimum age - /// What is the context for this request; used to access the Span - void Archive(TimeSpan dispatchedSince, RequestContext requestContext); - - /// - /// Archive Message from the outbox to the outbox archive provider - /// - /// How stale is the message that we want to archive - /// The context for the request pipeline; gives us the OTel span for example - /// The Cancellation Token - Task ArchiveAsync(TimeSpan dispatchedSince, RequestContext requestContext, CancellationToken cancellationToken); - /// /// Used with RPC to call a remote service via the external bus /// diff --git a/src/Paramore.Brighter/OutboxArchiver.cs b/src/Paramore.Brighter/OutboxArchiver.cs index 8e50f7a182..cf78264860 100644 --- a/src/Paramore.Brighter/OutboxArchiver.cs +++ b/src/Paramore.Brighter/OutboxArchiver.cs @@ -23,8 +23,12 @@ THE SOFTWARE. */ #endregion using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Paramore.Brighter.Logging; +using Paramore.Brighter.Observability; namespace Paramore.Brighter { @@ -33,12 +37,43 @@ namespace Paramore.Brighter /// /// The type of message to archive /// The transaction type of the Db - public class OutboxArchiver( - IAmAnExternalBusService bus, - IAmARequestContextFactory? requestContextFactory = null) - where TMessage : Message + public class OutboxArchiver where TMessage : Message { - private readonly IAmARequestContextFactory _requestContextFactory = requestContextFactory ?? new InMemoryRequestContextFactory(); + private static readonly ILogger s_logger = ApplicationLogging.CreateLogger>(); + private readonly IAmARequestContextFactory _requestContextFactory; + private readonly IAmAnOutboxSync? _outBox; + private readonly IAmAnOutboxAsync? _asyncOutbox; + private readonly IAmAnArchiveProvider _archiveProvider; + private readonly int _archiveBatchSize; + private readonly IAmABrighterTracer? _tracer; + private readonly InstrumentationOptions _instrumentationOptions; + + /// + /// Used to archive messages from an Outbox + /// + /// The type of message to archive + /// The transaction type of the Db + public OutboxArchiver( + IAmAnOutbox outbox, + IAmAnArchiveProvider archiveProvider, + IAmARequestContextFactory? requestContextFactory = null, + int archiveBatchSize = 100, + IAmABrighterTracer? tracer = null, + InstrumentationOptions instrumentationOptions = InstrumentationOptions.All) + { + _archiveProvider = archiveProvider; + _archiveBatchSize = archiveBatchSize; + _tracer = tracer; + _instrumentationOptions = instrumentationOptions; + _requestContextFactory = requestContextFactory ?? new InMemoryRequestContextFactory(); + + if (outbox is IAmAnOutboxSync syncOutbox) _outBox = syncOutbox; + if (outbox is IAmAnOutboxAsync asyncOutbox) _asyncOutbox = asyncOutbox; + } + + private const string NoSyncOutboxError = "A sync Outbox must be defined."; + private const string NoArchiveProviderError = "An Archive Provider must be defined."; + private const string NoAsyncOutboxError = "An async Outbox must be defined."; /// /// Archive Message from the outbox to the outbox archive provider @@ -50,7 +85,49 @@ public class OutboxArchiver( public void Archive(TimeSpan dispatchedSince, RequestContext? requestContext = null) { requestContext ??= _requestContextFactory.Create(); - bus.Archive(dispatchedSince, requestContext); + //This is an archive span parent; we expect individual archiving operations for messages to have their own spans + var parentSpan = requestContext.Span; + var span = _tracer?.CreateArchiveSpan(requestContext.Span, dispatchedSince, options: _instrumentationOptions); + requestContext.Span = span; + + try + { + if (_outBox is null) throw new ArgumentException(NoSyncOutboxError); + if (_archiveProvider is null) throw new ArgumentException(NoArchiveProviderError); + var messages = _outBox + .DispatchedMessages(dispatchedSince, requestContext, _archiveBatchSize) + .ToArray(); + + s_logger.LogInformation( + "Found {NumberOfMessageArchived} message to archive, batch size : {BatchSize}", + messages.Count(), _archiveBatchSize + ); + + if (messages.Length <= 0) return; + + foreach (var message in messages) + { + _archiveProvider.ArchiveMessage(message); + } + + _outBox.Delete(messages.Select(e => e.Id).ToArray(), requestContext); + + s_logger.LogInformation( + "Successfully archived {NumberOfMessageArchived}, batch size : {BatchSize}", + messages.Count(), _archiveBatchSize + ); + } + catch (Exception e) + { + s_logger.LogError(e, "Error while archiving from the outbox"); + _tracer?.AddExceptionToSpan(span, [e]); + throw; + } + finally + { + _tracer?.EndSpan(span); + requestContext.Span = parentSpan; + } } /// @@ -64,7 +141,46 @@ public void Archive(TimeSpan dispatchedSince, RequestContext? requestContext = n public async Task ArchiveAsync(TimeSpan dispatchedSince, RequestContext? requestContext = null, CancellationToken cancellationToken = default) { requestContext ??= _requestContextFactory.Create(); - await bus.ArchiveAsync(dispatchedSince, requestContext, cancellationToken); + //This is an archive span parent; we expect individual archiving operations for messages to have their own spans + var parentSpan = requestContext.Span; + var span = _tracer?.CreateArchiveSpan(requestContext.Span, dispatchedSince, options: _instrumentationOptions); + requestContext.Span = span; + + try + { + if (_asyncOutbox is null) throw new ArgumentException(NoAsyncOutboxError); + if (_archiveProvider is null) throw new ArgumentException(NoArchiveProviderError); + var messages = (await _asyncOutbox.DispatchedMessagesAsync( + dispatchedSince, requestContext, pageSize: _archiveBatchSize, + cancellationToken: cancellationToken + )).ToArray(); + + if (messages.Length <= 0) + { + } + else + { + foreach (var message in messages) + { + await _archiveProvider.ArchiveMessageAsync(message, cancellationToken); + } + + await _asyncOutbox.DeleteAsync(messages.Select(e => e.Id).ToArray(), requestContext, + cancellationToken: cancellationToken + ); + } + } + catch (Exception e) + { + s_logger.LogError(e, "Error while archiving from the outbox"); + _tracer?.AddExceptionToSpan(span, [e]); + throw; + } + finally + { + _tracer?.EndSpan(span); + requestContext.Span = parentSpan; + } } } } diff --git a/tests/Paramore.Brighter.Core.Tests/Archiving/When_Archiving_Old_Messages_From_The_Outbox.cs b/tests/Paramore.Brighter.Core.Tests/Archiving/When_Archiving_Old_Messages_From_The_Outbox.cs index faf312617a..685623b621 100644 --- a/tests/Paramore.Brighter.Core.Tests/Archiving/When_Archiving_Old_Messages_From_The_Outbox.cs +++ b/tests/Paramore.Brighter.Core.Tests/Archiving/When_Archiving_Old_Messages_From_The_Outbox.cs @@ -3,10 +3,7 @@ using System.Transactions; using FluentAssertions; using Microsoft.Extensions.Time.Testing; -using Paramore.Brighter.Core.Tests.CommandProcessors.TestDoubles; using Paramore.Brighter.Observability; -using Polly; -using Polly.Registry; using Xunit; namespace Paramore.Brighter.Core.Tests.Archiving; @@ -15,52 +12,23 @@ public class ServiceBusMessageStoreArchiverTests { private readonly InMemoryOutbox _outbox; private readonly InMemoryArchiveProvider _archiveProvider; - private readonly ExternalBusService _bus; private readonly FakeTimeProvider _timeProvider; private readonly RoutingKey _routingKey = new("MyTopic"); + private readonly OutboxArchiver _archiver; public ServiceBusMessageStoreArchiverTests() { _timeProvider = new FakeTimeProvider(); - var producer = new InMemoryProducer(new InternalBus(), _timeProvider){Publication = {Topic = _routingKey, RequestType = typeof(MyCommand)}}; - var messageMapperRegistry = new MessageMapperRegistry( - new SimpleMessageMapperFactory((_) => new MyCommandMessageMapper()), - null); - - var retryPolicy = Policy - .Handle() - .Retry(); - - var circuitBreakerPolicy = Policy - .Handle() - .CircuitBreaker(1, TimeSpan.FromMilliseconds(1)); - - var producerRegistry = new ProducerRegistry(new Dictionary - { - { _routingKey, producer }, - }); - - var policyRegistry = new PolicyRegistry - { - { CommandProcessor.RETRYPOLICY, retryPolicy }, - { CommandProcessor.CIRCUITBREAKER, circuitBreakerPolicy } - }; - var tracer = new BrighterTracer(); _outbox = new InMemoryOutbox(_timeProvider){Tracer = tracer}; _archiveProvider = new InMemoryArchiveProvider(); - - _bus = new ExternalBusService( - producerRegistry, - policyRegistry, - messageMapperRegistry, - new EmptyMessageTransformerFactory(), - new EmptyMessageTransformerFactoryAsync(), - tracer, + + _archiver = new OutboxArchiver( _outbox, - _archiveProvider - ); + _archiveProvider + ); + } [Fact] @@ -86,7 +54,7 @@ public void When_Archiving_All_Messages_From_The_Outbox() _timeProvider.Advance(TimeSpan.FromMinutes(15)); - _bus.Archive(TimeSpan.FromMilliseconds(500), context); + _archiver.Archive(TimeSpan.FromMilliseconds(500), context); //assert _outbox.EntryCount.Should().Be(0); @@ -116,7 +84,7 @@ public void When_Archiving_Some_Messages_From_The_Outbox() _timeProvider.Advance(TimeSpan.FromSeconds(30)); - _bus.Archive(TimeSpan.FromSeconds(30), context); + _archiver.Archive(TimeSpan.FromSeconds(30), context); //assert _outbox.EntryCount.Should().Be(1); @@ -142,7 +110,7 @@ public void When_Archiving_No_Messages_From_The_Outbox() //act _outbox.EntryCount.Should().Be(3); - _bus.Archive(TimeSpan.FromMilliseconds(20000), context); + _archiver.Archive(TimeSpan.FromMilliseconds(20000), context); //assert _outbox.EntryCount.Should().Be(3); @@ -155,7 +123,7 @@ public void When_Archiving_No_Messages_From_The_Outbox() public void When_Archiving_An_Empty_The_Outbox() { var context = new RequestContext(); - _bus.Archive(TimeSpan.FromMilliseconds(20000), context); + _archiver.Archive(TimeSpan.FromMilliseconds(20000), context); //assert _outbox.EntryCount.Should().Be(0); diff --git a/tests/Paramore.Brighter.Core.Tests/Archiving/When_Archiving_Old_Messages_From_The_Outbox_Async.cs b/tests/Paramore.Brighter.Core.Tests/Archiving/When_Archiving_Old_Messages_From_The_Outbox_Async.cs index 339ce3d524..e148c48f72 100644 --- a/tests/Paramore.Brighter.Core.Tests/Archiving/When_Archiving_Old_Messages_From_The_Outbox_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/Archiving/When_Archiving_Old_Messages_From_The_Outbox_Async.cs @@ -1,14 +1,10 @@ using System; using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; using System.Transactions; using FluentAssertions; using Microsoft.Extensions.Time.Testing; -using Paramore.Brighter.Core.Tests.CommandProcessors.TestDoubles; using Paramore.Brighter.Observability; -using Polly; -using Polly.Registry; using Xunit; namespace Paramore.Brighter.Core.Tests.Archiving; @@ -17,57 +13,19 @@ public class ServiceBusMessageStoreArchiverTestsAsync { private readonly InMemoryOutbox _outbox; private readonly InMemoryArchiveProvider _archiveProvider; - private readonly ExternalBusService _bus; private readonly FakeTimeProvider _timeProvider; private readonly RoutingKey _routingKey = new("MyTopic"); + private readonly OutboxArchiver _archiver; public ServiceBusMessageStoreArchiverTestsAsync() { - var producer = new InMemoryProducer(new InternalBus(), new FakeTimeProvider()) - { - Publication = {Topic = _routingKey, RequestType = typeof(MyCommand)} - }; - - var messageMapperRegistry = new MessageMapperRegistry( - null, - new SimpleMessageMapperFactoryAsync((_) => new MyCommandMessageMapperAsync()) - ); - - var retryPolicy = Policy - .Handle() - .RetryAsync(); - - var circuitBreakerPolicy = Policy - .Handle() - .CircuitBreakerAsync(1, TimeSpan.FromMilliseconds(1)); - - var producerRegistry = new ProducerRegistry(new Dictionary - { - { _routingKey, producer }, - }); - - var policyRegistry = new PolicyRegistry - { - { CommandProcessor.RETRYPOLICYASYNC, retryPolicy }, - { CommandProcessor.CIRCUITBREAKERASYNC, circuitBreakerPolicy } - }; - _timeProvider = new FakeTimeProvider(); var tracer = new BrighterTracer(); _outbox = new InMemoryOutbox(_timeProvider){Tracer = tracer}; _archiveProvider = new InMemoryArchiveProvider(); - _bus = new ExternalBusService( - producerRegistry, - policyRegistry, - messageMapperRegistry, - new EmptyMessageTransformerFactory(), - new EmptyMessageTransformerFactoryAsync(), - tracer, - _outbox, - _archiveProvider - ); - + _archiver = new OutboxArchiver(_outbox, _archiveProvider); + } [Fact] @@ -92,7 +50,7 @@ public async Task When_Archiving_Old_Messages_From_The_Outbox() _timeProvider.Advance(TimeSpan.FromSeconds(30)); - await _bus.ArchiveAsync(TimeSpan.FromSeconds(15), context, new CancellationToken()); + await _archiver.ArchiveAsync(TimeSpan.FromSeconds(15), context); //assert _outbox.EntryCount.Should().Be(0); @@ -122,7 +80,7 @@ public async Task When_Archiving_Some_Messages_From_The_Outbox() _timeProvider.Advance(TimeSpan.FromSeconds(30)); - await _bus.ArchiveAsync(TimeSpan.FromSeconds(15), context, new CancellationToken()); + await _archiver.ArchiveAsync(TimeSpan.FromSeconds(15), context); //assert _outbox.EntryCount.Should().Be(1); @@ -148,7 +106,7 @@ public async Task When_Archiving_No_Messages_From_The_Outbox() //act _outbox.EntryCount.Should().Be(3); - await _bus.ArchiveAsync(TimeSpan.FromMilliseconds(20000), context, new CancellationToken()); + await _archiver.ArchiveAsync(TimeSpan.FromMilliseconds(20000), context); //assert _outbox.EntryCount.Should().Be(3); @@ -164,7 +122,7 @@ public async Task When_Archiving_An_Empty_Outbox() var context = new RequestContext(); //act - await _bus.ArchiveAsync(TimeSpan.FromMilliseconds(20000), context, new CancellationToken()); + await _archiver.ArchiveAsync(TimeSpan.FromMilliseconds(20000), context); //assert _outbox.EntryCount.Should().Be(0); diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs index 70ae8ad58d..24aa6c5d67 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs @@ -25,6 +25,7 @@ public class ExternalServiceBusArchiveObservabilityTests private RoutingKey _routingKey = new("MyEvent"); private readonly InMemoryOutbox _outbox; private readonly TracerProvider _traceProvider; + private readonly OutboxArchiver _archiver; private const double TOLERANCE = 0.000000001; public ExternalServiceBusArchiveObservabilityTests() @@ -73,6 +74,8 @@ public ExternalServiceBusArchiveObservabilityTests() _outbox = new InMemoryOutbox(_timeProvider) { Tracer = tracer }; var archiveProvider = new InMemoryArchiveProvider(); + _archiver = new OutboxArchiver(_outbox, archiveProvider, tracer: tracer); + _bus = new ExternalBusService( producerRegistry, policyRegistry, @@ -81,7 +84,6 @@ public ExternalServiceBusArchiveObservabilityTests() new EmptyMessageTransformerFactoryAsync(), tracer, _outbox, - archiveProvider, timeProvider:_timeProvider); } @@ -107,7 +109,7 @@ public void When_archiving_from_the_outbox() //archive var dispatchedSince = TimeSpan.FromSeconds(100); - _bus.Archive(dispatchedSince, context); + _archiver.Archive(dispatchedSince, context); //should be no messages in the outbox _outbox.EntryCount.Should().Be(0); @@ -135,8 +137,8 @@ public void When_archiving_from_the_outbox() //check for delete messages span var deleteActivity = _exportedActivities.SingleOrDefault(a => a.DisplayName == $"{OutboxDbOperation.Delete.ToSpanName()} {InMemoryAttributes.DbName} {InMemoryAttributes.DbTable}"); - deleteActivity.Should().NotBeNull(); - deleteActivity.ParentId.Should().Be(createActivity.Id); + deleteActivity?.Should().NotBeNull(); + deleteActivity?.ParentId.Should().Be(createActivity.Id); //check the tags for the create span createActivity.TagObjects.Should().Contain(t => t.Key == BrighterSemanticConventions.ArchiveAge && Math.Abs(Convert.ToDouble(t.Value) - dispatchedSince.TotalMilliseconds) < TOLERANCE); diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox_async.cs b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox_async.cs index aa3cc57638..e08326743b 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox_async.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox_async.cs @@ -24,9 +24,10 @@ public class AsyncExternalServiceBusArchiveObservabilityTests private readonly ExternalBusService _bus; private readonly Publication _publication; private readonly FakeTimeProvider _timeProvider; - private RoutingKey _routingKey = new("MyEvent"); + private readonly RoutingKey _routingKey = new("MyEvent"); private readonly InMemoryOutbox _outbox; private readonly TracerProvider _traceProvider; + private readonly OutboxArchiver _archiver; private const double TOLERANCE = 0.000000001; public AsyncExternalServiceBusArchiveObservabilityTests() @@ -75,6 +76,8 @@ public AsyncExternalServiceBusArchiveObservabilityTests() _outbox = new InMemoryOutbox(_timeProvider) { Tracer = tracer }; var archiveProvider = new InMemoryArchiveProvider(); + _archiver = new OutboxArchiver(_outbox, archiveProvider, tracer: tracer); + _bus = new ExternalBusService( producerRegistry, policyRegistry, @@ -83,7 +86,6 @@ public AsyncExternalServiceBusArchiveObservabilityTests() new EmptyMessageTransformerFactoryAsync(), tracer, _outbox, - archiveProvider, timeProvider:_timeProvider); } @@ -109,7 +111,7 @@ public async Task When_archiving_from_the_outbox() //archive var dispatchedSince = TimeSpan.FromSeconds(100); - await _bus.ArchiveAsync(dispatchedSince, context); + await _archiver.ArchiveAsync(dispatchedSince, context); //should be no messages in the outbox _outbox.EntryCount.Should().Be(0); From b20e35723b11a96cd568b33bdbe931295885bbae Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Mon, 28 Oct 2024 09:55:51 +0000 Subject: [PATCH 12/15] feat: rename of ExternalBusService.cs to OutboxProducerMediator.cs --- .../ServiceCollectionExtensions.cs | 10 +-- .../ControlBus/ControlBusReceiverBuilder.cs | 2 +- src/Paramore.Brighter/CommandProcessor.cs | 63 +++++++++---------- .../CommandProcessorBuilder.cs | 6 +- .../ControlBusSenderFactory.cs | 2 +- ...vice.cs => IAmAnOutboxProducerMediator.cs} | 4 +- ...usService.cs => OutboxProducerMediator.cs} | 14 +++-- ...ling_A_Server_Via_The_Command_Processor.cs | 2 +- ...The_Command_Processor_With_No_In_Mapper.cs | 2 +- ...he_Command_Processor_With_No_Out_Mapper.cs | 2 +- ...a_The_Command_Processor_With_No_Timeout.cs | 2 +- ..._PostBox_On_The_Command_Processor_Async.cs | 2 +- ...PostBox_On_The_Command_Processor _Async.cs | 2 +- ...ng_The_PostBox_On_The_Command_Processor.cs | 2 +- ...ng_The_PostBox_On_The_Command_Processor.cs | 2 +- ..._PostBox_On_The_Command_Processor_Async.cs | 2 +- ...positing_A_Message_In_The_Message_Store.cs | 2 +- ...ing_A_Message_In_The_Message_StoreAsync.cs | 2 +- ..._Message_In_The_Message_StoreAsync_Bulk.cs | 2 +- ...ing_A_Message_In_The_Message_Store_Bulk.cs | 2 +- ...And_There_Is_No_Message_Mapper_Registry.cs | 2 +- ...ere_Is_No_Message_Mapper_Registry_Async.cs | 2 +- ...essage_And_There_Is_No_Message_Producer.cs | 2 +- ...age_And_There_Is_No_Message_Transformer.cs | 2 +- ...d_There_Is_No_Message_Transformer_Async.cs | 2 +- ...ting_A_Message_To_The_Command_Processor.cs | 2 +- ..._Message_To_The_Command_Processor_Async.cs | 2 +- ..._Limit_Total_Writes_To_OutBox_In_Window.cs | 2 +- .../When_Posting_Via_A_Control_Bus_Sender.cs | 2 +- ..._Posting_Via_A_Control_Bus_Sender_Async.cs | 2 +- .../When_Posting_With_A_Default_Policy.cs | 2 +- ...Posting_With_An_In_Memory_Message_Store.cs | 2 +- ...g_With_An_In_Memory_Message_Store_Async.cs | 2 +- .../When_A_Request_Context_Is_Provided.cs | 8 +-- .../When_No_Request_Context_Is_Provided.cs | 8 +-- .../Archive/When_archiving_from_the_outbox.cs | 4 +- .../When_archiving_from_the_outbox_async.cs | 4 +- ...n_Clearing_A_Message_A_Span_Is_Exported.cs | 2 +- ...ring_A_Message_A_Span_Is_Exported_Async.cs | 2 +- ...ipile_Messages_Spans_Are_Exported_Async.cs | 2 +- ...ng_Multiple_Messages_Spans_Are_Exported.cs | 2 +- ...Outstanding_Messages_Spans_Are_Exported.cs | 2 +- ...anding_Messages_Spans_Are_Exported_Bulk.cs | 2 +- ...Depositing_A_Request_A_Span_Is_Exported.cs | 2 +- ...ting_A_Request_A_Span_Is_Exported_Async.cs | 2 +- ...ng_Multiple_Requests_Spans_Are_Exported.cs | 2 +- ...tiple_Requests_Spans_Are_Exported_Async.cs | 2 +- .../Sweeper/When_sweeping_the_outbox.cs | 8 +-- 48 files changed, 102 insertions(+), 103 deletions(-) rename src/Paramore.Brighter/{IAmAnExternalBusService.cs => IAmAnOutboxProducerMediator.cs} (98%) rename src/Paramore.Brighter/{ExternalBusService.cs => OutboxProducerMediator.cs} (98%) diff --git a/src/Paramore.Brighter.Extensions.DependencyInjection/ServiceCollectionExtensions.cs b/src/Paramore.Brighter.Extensions.DependencyInjection/ServiceCollectionExtensions.cs index 3d47010db5..e20f1776b4 100644 --- a/src/Paramore.Brighter.Extensions.DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Paramore.Brighter.Extensions.DependencyInjection/ServiceCollectionExtensions.cs @@ -222,7 +222,7 @@ public static IBrighterBuilder UseExternalBus( brighterBuilder.Services.TryAddSingleton(busConfiguration); - brighterBuilder.Services.TryAdd(new ServiceDescriptor(typeof(IAmAnExternalBusService), + brighterBuilder.Services.TryAdd(new ServiceDescriptor(typeof(IAmAnOutboxProducerMediator), (serviceProvider) => BuildExternalBus( serviceProvider, transactionType, busConfiguration, brighterBuilder.PolicyRegistry, outbox ), @@ -237,7 +237,7 @@ private static INeedInstrumentation AddEventBus( INeedMessaging messagingBuilder, IUseRpc useRequestResponse) { - var eventBus = provider.GetService(); + var eventBus = provider.GetService(); var eventBusConfiguration = provider.GetService(); var serviceActivatorOptions = provider.GetService(); @@ -325,7 +325,7 @@ private static object BuildCommandProcessor(IServiceProvider provider) return commandProcessor; } - private static IAmAnExternalBusService BuildExternalBus(IServiceProvider serviceProvider, + private static IAmAnOutboxProducerMediator BuildExternalBus(IServiceProvider serviceProvider, Type transactionType, ExternalBusConfiguration busConfiguration, IPolicyRegistry policyRegistry, @@ -333,9 +333,9 @@ private static IAmAnExternalBusService BuildExternalBus(IServiceProvider service { //Because the bus has specialized types as members, we need to create the bus type dynamically //again to prevent someone configuring Brighter from having to pass generic types - var busType = typeof(ExternalBusService<,>).MakeGenericType(typeof(Message), transactionType); + var busType = typeof(OutboxProducerMediator<,>).MakeGenericType(typeof(Message), transactionType); - return (IAmAnExternalBusService)Activator.CreateInstance( + return (IAmAnOutboxProducerMediator)Activator.CreateInstance( busType, busConfiguration.ProducerRegistry, policyRegistry, diff --git a/src/Paramore.Brighter.ServiceActivator/ControlBus/ControlBusReceiverBuilder.cs b/src/Paramore.Brighter.ServiceActivator/ControlBus/ControlBusReceiverBuilder.cs index 87d50ee781..a175d10c23 100644 --- a/src/Paramore.Brighter.ServiceActivator/ControlBus/ControlBusReceiverBuilder.cs +++ b/src/Paramore.Brighter.ServiceActivator/ControlBus/ControlBusReceiverBuilder.cs @@ -158,7 +158,7 @@ public Dispatcher Build(string hostName) var outbox = new SinkOutboxSync(); - var externalBus = new ExternalBusService( + var externalBus = new OutboxProducerMediator( producerRegistry: producerRegistry, policyRegistry: new DefaultPolicy(), mapperRegistry: outgoingMessageMapperRegistry, diff --git a/src/Paramore.Brighter/CommandProcessor.cs b/src/Paramore.Brighter/CommandProcessor.cs index e900a4cf68..b8225cb0e5 100644 --- a/src/Paramore.Brighter/CommandProcessor.cs +++ b/src/Paramore.Brighter/CommandProcessor.cs @@ -101,9 +101,9 @@ public class CommandProcessor : IAmACommandProcessor /// Bus: We want to hold a reference to the bus; use double lock to let us pass parameters to the constructor from the first instance /// MethodCache: Used to reduce the cost of reflection for bulk calls /// - private static IAmAnExternalBusService? s_bus; + private static IAmAnOutboxProducerMediator? s_outboxProducerMediator; private static readonly object s_padlock = new(); - private static ConcurrentDictionary s_boundDepositCalls = new(); + private static readonly ConcurrentDictionary s_boundDepositCalls = new(); /// /// Initializes a new instance of the class @@ -167,7 +167,7 @@ public CommandProcessor( IAmAHandlerFactory handlerFactory, IAmARequestContextFactory requestContextFactory, IPolicyRegistry policyRegistry, - IAmAnExternalBusService bus, + IAmAnOutboxProducerMediator bus, IAmAFeatureSwitchRegistry? featureSwitchRegistry = null, InboxConfiguration? inboxConfiguration = null, IEnumerable? replySubscriptions = null, @@ -199,7 +199,7 @@ public CommandProcessor( public CommandProcessor( IAmARequestContextFactory requestContextFactory, IPolicyRegistry policyRegistry, - IAmAnExternalBusService bus, + IAmAnOutboxProducerMediator bus, IAmAFeatureSwitchRegistry? featureSwitchRegistry = null, InboxConfiguration? inboxConfiguration = null, IEnumerable? replySubscriptions = null, @@ -562,16 +562,16 @@ public string DepositPost( try { - Message message = s_bus!.CreateMessageFromRequest(request, context); + Message message = s_outboxProducerMediator!.CreateMessageFromRequest(request, context); - var bus = ((IAmAnExternalBusService)s_bus); + var bus = ((IAmAnOutboxProducerMediator)s_outboxProducerMediator); if (!bus.HasOutbox()) throw new InvalidOperationException("No outbox defined."); bus.AddToOutbox(message, context, transactionProvider, batchId); - return message.Id!; + return message.Id; } catch (Exception e) { @@ -632,9 +632,9 @@ public string[] DepositPost( { var successfullySentMessage = new List(); - var bus = (IAmAnExternalBusService)s_bus!; + var mediator = (IAmAnOutboxProducerMediator)s_outboxProducerMediator!; - var batchId = bus.StartBatchAddToOutbox(); + var batchId = mediator.StartBatchAddToOutbox(); foreach (var request in requests) { @@ -644,7 +644,7 @@ public string[] DepositPost( context.Span = createSpan; } - bus.EndBatchAddToOutbox(batchId, transactionProvider, context); + mediator.EndBatchAddToOutbox(batchId, transactionProvider, context); return successfullySentMessage.ToArray(); } @@ -758,9 +758,9 @@ public async Task DepositPostAsync( try { - Message message = await s_bus!.CreateMessageFromRequestAsync(request, context, cancellationToken); + Message message = await s_outboxProducerMediator!.CreateMessageFromRequestAsync(request, context, cancellationToken); - var bus = ((IAmAnExternalBusService)s_bus); + var bus = ((IAmAnOutboxProducerMediator)s_outboxProducerMediator); if (!bus.HasAsyncOutbox()) throw new InvalidOperationException("No async outbox defined."); @@ -768,7 +768,7 @@ public async Task DepositPostAsync( await bus.AddToOutboxAsync(message, context, transactionProvider, continueOnCapturedContext, cancellationToken, batchId); - return message.Id!; + return message.Id; } catch (Exception e) { @@ -843,7 +843,7 @@ public async Task DepositPostAsync( { var successfullySentMessage = new List(); - var bus = (IAmAnExternalBusService)s_bus!; + var bus = (IAmAnOutboxProducerMediator)s_outboxProducerMediator!; var batchId = bus.StartBatchAddToOutbox(); @@ -919,7 +919,7 @@ public void ClearOutbox(string[] ids, RequestContext? requestContext = null, Dic try { - s_bus!.ClearOutbox(ids, context, args); + s_outboxProducerMediator!.ClearOutbox(ids, context, args); } catch (Exception e) { @@ -953,7 +953,7 @@ public async Task ClearOutboxAsync( try { - await s_bus!.ClearOutboxAsync(posts, context, continueOnCapturedContext, args, cancellationToken); + await s_outboxProducerMediator!.ClearOutboxAsync(posts, context, continueOnCapturedContext, args, cancellationToken); } catch (Exception e) { @@ -990,7 +990,7 @@ public void ClearOutstandingFromOutbox( try { var minAge = minimumAge ?? TimeSpan.FromMilliseconds(5000); - s_bus!.ClearOutstandingFromOutbox(amountToClear, minAge, useBulk, context, args); + s_outboxProducerMediator!.ClearOutstandingFromOutbox(amountToClear, minAge, useBulk, context, args); } catch (Exception e) { @@ -1028,10 +1028,10 @@ public void ClearOutstandingFromOutbox( var subscription = _replySubscriptions?.FirstOrDefault(s => s.DataType == typeof(TResponse)); if (subscription is null) - throw new ArgumentOutOfRangeException($"No Subscription registered fpr replies of type {typeof(T)}"); + throw new InvalidOperationException($"No Subscription registered fpr replies of type {typeof(T)}"); if (_responseChannelFactory is null) - throw new ArgumentOutOfRangeException("No ResponseChannelFactory registered"); + throw new InvalidOperationException("No ResponseChannelFactory registered"); //create a reply queue via creating a consumer - we use random identifiers as we will destroy var channelName = Guid.NewGuid(); @@ -1055,11 +1055,11 @@ public void ClearOutstandingFromOutbox( try { - var outMessage = s_bus!.CreateMessageFromRequest(request, context); + var outMessage = s_outboxProducerMediator!.CreateMessageFromRequest(request, context); //We don't store the message, if we continue to fail further retry is left to the sender s_logger.LogDebug("Sending request with routingkey {ChannelName}", channelName); - s_bus.CallViaExternalBus(outMessage, requestContext); + s_outboxProducerMediator.CallViaExternalBus(outMessage, requestContext); Message? responseMessage = null; @@ -1071,7 +1071,7 @@ public void ClearOutstandingFromOutbox( { s_logger.LogDebug("Reply received from {ChannelName}", channelName); //map to request is map to a response, but it is a request from consumer point of view. Confusing, but... - s_bus.CreateRequestFromMessage(responseMessage, context, out TResponse response); + s_outboxProducerMediator.CreateRequestFromMessage(responseMessage, context, out TResponse response); Send(response); return response; @@ -1099,15 +1099,12 @@ public void ClearOutstandingFromOutbox( /// public static void ClearServiceBus() { - if (s_bus != null) + if (s_outboxProducerMediator != null) { lock (s_padlock) { - if (s_bus != null) - { - s_bus.Dispose(); - s_bus = null; - } + s_outboxProducerMediator.Dispose(); + s_outboxProducerMediator = null; } } s_boundDepositCalls.Clear(); @@ -1130,7 +1127,7 @@ private bool HandlerFactoryIsNotEitherIAmAHandlerFactorySyncOrAsync(IAmAHandlerF { // If we do not have a subscriber registry and we do not have a handler factory // then we're creating a control bus sender and we don't need them - if (_subscriberRegistry is null && handlerFactory is null) + if (_subscriberRegistry is null) return false; switch (handlerFactory) @@ -1143,16 +1140,16 @@ private bool HandlerFactoryIsNotEitherIAmAHandlerFactorySyncOrAsync(IAmAHandlerF } } - // Create an instance of the ExternalBusService if one not already set for this app. Note that we do not support reinitialization here, so once you have + // Create an instance of the OutboxProducerMediator if one not already set for this app. Note that we do not support reinitialization here, so once you have // set a command processor for the app, you can't call init again to set them - although the properties are not read-only so overwriting is possible // if needed as a "get out of gaol" card. - private static void InitExtServiceBus(IAmAnExternalBusService bus) + private static void InitExtServiceBus(IAmAnOutboxProducerMediator bus) { - if (s_bus == null) + if (s_outboxProducerMediator == null) { lock (s_padlock) { - s_bus ??= bus; + s_outboxProducerMediator ??= bus; } } } diff --git a/src/Paramore.Brighter/CommandProcessorBuilder.cs b/src/Paramore.Brighter/CommandProcessorBuilder.cs index 6dd91234f8..10217804e3 100644 --- a/src/Paramore.Brighter/CommandProcessorBuilder.cs +++ b/src/Paramore.Brighter/CommandProcessorBuilder.cs @@ -86,7 +86,7 @@ public class CommandProcessorBuilder : INeedAHandlers, INeedPolicy, INeedMessagi private IPolicyRegistry? _policyRegistry; private IAmAFeatureSwitchRegistry? _featureSwitchRegistry; - private IAmAnExternalBusService? _bus; + private IAmAnOutboxProducerMediator? _bus; private bool _useRequestReplyQueues; private IAmAChannelFactory? _responseChannelFactory; private IEnumerable? _replySubscriptions; @@ -174,7 +174,7 @@ public INeedMessaging DefaultPolicy() /// public INeedInstrumentation ExternalBus( ExternalBusType busType, - IAmAnExternalBusService bus, + IAmAnOutboxProducerMediator bus, IAmAChannelFactory? responseChannelFactory = null, IEnumerable? subscriptions = null, InboxConfiguration? inboxConfiguration = null @@ -372,7 +372,7 @@ public interface INeedMessaging /// INeedInstrumentation ExternalBus( ExternalBusType busType, - IAmAnExternalBusService bus, + IAmAnOutboxProducerMediator bus, IAmAChannelFactory? responseChannelFactory = null, IEnumerable? subscriptions = null, InboxConfiguration? inboxConfiguration = null diff --git a/src/Paramore.Brighter/ControlBusSenderFactory.cs b/src/Paramore.Brighter/ControlBusSenderFactory.cs index 936b0e2819..5e02c9064f 100644 --- a/src/Paramore.Brighter/ControlBusSenderFactory.cs +++ b/src/Paramore.Brighter/ControlBusSenderFactory.cs @@ -49,7 +49,7 @@ public IAmAControlBusSender Create(IAmAnOutbox outbox, IAmAProd null); mapper.Register(); - var bus = new ExternalBusService( + var bus = new OutboxProducerMediator( producerRegistry: producerRegistry, policyRegistry: new DefaultPolicy(), mapperRegistry: mapper, diff --git a/src/Paramore.Brighter/IAmAnExternalBusService.cs b/src/Paramore.Brighter/IAmAnOutboxProducerMediator.cs similarity index 98% rename from src/Paramore.Brighter/IAmAnExternalBusService.cs rename to src/Paramore.Brighter/IAmAnOutboxProducerMediator.cs index f588cf5431..f754cc6fa1 100644 --- a/src/Paramore.Brighter/IAmAnExternalBusService.cs +++ b/src/Paramore.Brighter/IAmAnOutboxProducerMediator.cs @@ -9,7 +9,7 @@ namespace Paramore.Brighter /// An external bus service allows us to send messages to external systems /// The interaction with the CommandProcessor is mostly via the Outbox and the Message Mapper /// - public interface IAmAnExternalBusService : IDisposable + public interface IAmAnOutboxProducerMediator : IDisposable { /// /// Used with RPC to call a remote service via the external bus @@ -103,7 +103,7 @@ void CreateRequestFromMessage(Message message, RequestContext? request /// An external bus service allows us to send messages to external systems /// The interaction with the CommandProcessor is mostly via the Outbox and the Message Mapper /// - public interface IAmAnExternalBusService : IDisposable + public interface IAmAnOutboxProducerMediator : IDisposable { /// /// Adds a message to the outbox diff --git a/src/Paramore.Brighter/ExternalBusService.cs b/src/Paramore.Brighter/OutboxProducerMediator.cs similarity index 98% rename from src/Paramore.Brighter/ExternalBusService.cs rename to src/Paramore.Brighter/OutboxProducerMediator.cs index f9f18c89c7..a094d0770c 100644 --- a/src/Paramore.Brighter/ExternalBusService.cs +++ b/src/Paramore.Brighter/OutboxProducerMediator.cs @@ -16,11 +16,12 @@ namespace Paramore.Brighter { /// - /// Provide services to CommandProcessor that persist across the lifetime of the application. Allows separation from - /// elements that have a lifetime linked to the scope of a request, or are transient for DI purposes + /// Mediates the interaction between a producer and an outbox. As we want to write to the outbox, and then send from there + /// to the producer, we need to take control of produce operations to mediate between the two in a transaction. + /// NOTE: This class is singleton. The CommandProcessor by contrast, is transient or more typically scoped. /// - public class ExternalBusService : IAmAnExternalBusService, - IAmAnExternalBusService + public class OutboxProducerMediator : IAmAnOutboxProducerMediator, + IAmAnOutboxProducerMediator where TMessage : Message { private static readonly ILogger s_logger = ApplicationLogging.CreateLogger(); @@ -58,7 +59,7 @@ public class ExternalBusService : IAmAnExternalBusServic private readonly TimeProvider _timeProvider; /// - /// Creates an instance of External Bus Services + /// Creates an instance of the Outbox Producer Mediator /// /// A registry of producers /// A registry for reliability policies @@ -74,7 +75,8 @@ public class ExternalBusService : IAmAnExternalBusServic /// An outbox may require additional arguments, such as a topic list to search /// /// How verbose do we want our instrumentation to be - public ExternalBusService(IAmAProducerRegistry producerRegistry, + public OutboxProducerMediator( + IAmAProducerRegistry producerRegistry, IPolicyRegistry policyRegistry, IAmAMessageMapperRegistry mapperRegistry, IAmAMessageTransformerFactory messageTransformerFactory, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor.cs index 63ccb5aa1c..3eb18c74e9 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor.cs @@ -76,7 +76,7 @@ public CommandProcessorCallTests() }); var tracer = new BrighterTracer(); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, _messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_In_Mapper.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_In_Mapper.cs index f8c1851037..7d55d51c70 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_In_Mapper.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_In_Mapper.cs @@ -63,7 +63,7 @@ public CommandProcessorNoInMapperTests() var tracer = new BrighterTracer(); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_Out_Mapper.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_Out_Mapper.cs index d84e69cadd..6879921d69 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_Out_Mapper.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_Out_Mapper.cs @@ -62,7 +62,7 @@ public CommandProcessorMissingOutMapperTests() }); var tracer = new BrighterTracer(timeProvider); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_Timeout.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_Timeout.cs index a73c6b88a9..612c9f4f5b 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_Timeout.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_Timeout.cs @@ -74,7 +74,7 @@ public CommandProcessorCallTestsNoTimeout() var timeProvider = fakeTimeProvider; var tracer = new BrighterTracer(timeProvider); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Bulk_Clearing_The_PostBox_On_The_Command_Processor_Async.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Bulk_Clearing_The_PostBox_On_The_Command_Processor_Async.cs index c868b34db2..4da0172e61 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Bulk_Clearing_The_PostBox_On_The_Command_Processor_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Bulk_Clearing_The_PostBox_On_The_Command_Processor_Async.cs @@ -101,7 +101,7 @@ public CommandProcessorPostBoxBulkClearAsyncTests() var tracer = new BrighterTracer(); _outbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Clearing_The_PostBox_On_The_Command_Processor _Async.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Clearing_The_PostBox_On_The_Command_Processor _Async.cs index 14ab071012..3f0ee5c83b 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Clearing_The_PostBox_On_The_Command_Processor _Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Clearing_The_PostBox_On_The_Command_Processor _Async.cs @@ -87,7 +87,7 @@ public CommandProcessorPostBoxClearAsyncTests() var tracer = new BrighterTracer(timeProvider); _outbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Clearing_The_PostBox_On_The_Command_Processor.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Clearing_The_PostBox_On_The_Command_Processor.cs index bcc3bafe7e..28594579cb 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Clearing_The_PostBox_On_The_Command_Processor.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Clearing_The_PostBox_On_The_Command_Processor.cs @@ -86,7 +86,7 @@ public CommandProcessorPostBoxClearTests() var tracer = new BrighterTracer(timeProvider); _outbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Implicit_Clearing_The_PostBox_On_The_Command_Processor.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Implicit_Clearing_The_PostBox_On_The_Command_Processor.cs index 2efc30ef07..1f77823fb3 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Implicit_Clearing_The_PostBox_On_The_Command_Processor.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Implicit_Clearing_The_PostBox_On_The_Command_Processor.cs @@ -95,7 +95,7 @@ public CommandProcessorPostBoxImplicitClearTests() var tracer = new BrighterTracer(); _outbox = new InMemoryOutbox(timeProvider){Tracer = tracer}; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Implicit_Clearing_The_PostBox_On_The_Command_Processor_Async.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Implicit_Clearing_The_PostBox_On_The_Command_Processor_Async.cs index 80eb790ec1..77706409ff 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Implicit_Clearing_The_PostBox_On_The_Command_Processor_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Clear/When_Implicit_Clearing_The_PostBox_On_The_Command_Processor_Async.cs @@ -95,7 +95,7 @@ public CommandProcessorPostBoxImplicitClearAsyncTests() _outbox = new InMemoryOutbox(timeProvider); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_Store.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_Store.cs index 1bacd42e4f..ab976bc9b1 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_Store.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_Store.cs @@ -67,7 +67,7 @@ public CommandProcessorDepositPostTests() var tracer = new BrighterTracer(); _fakeOutbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_StoreAsync.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_StoreAsync.cs index 600a0e3034..74f3aa3dc0 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_StoreAsync.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_StoreAsync.cs @@ -69,7 +69,7 @@ public CommandProcessorDepositPostTestsAsync() var tracer = new BrighterTracer(); _outbox = new InMemoryOutbox(timeProvider) { Tracer = tracer }; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_StoreAsync_Bulk.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_StoreAsync_Bulk.cs index 4f9ddc78ab..3623202dee 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_StoreAsync_Bulk.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_StoreAsync_Bulk.cs @@ -103,7 +103,7 @@ public CommandProcessorBulkDepositPostTestsAsync() var tracer = new BrighterTracer(new FakeTimeProvider()); _outbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_Store_Bulk.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_Store_Bulk.cs index 51898c9a20..a72d82b9b1 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_Store_Bulk.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Deposit/When_Depositing_A_Message_In_The_Message_Store_Bulk.cs @@ -99,7 +99,7 @@ public CommandProcessorBulkDepositPostTests() var tracer = new BrighterTracer(); _outbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Mapper_Registry.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Mapper_Registry.cs index 2961266938..31b78bd5df 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Mapper_Registry.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Mapper_Registry.cs @@ -80,7 +80,7 @@ public CommandProcessorNoMessageMapperTests() var tracer = new BrighterTracer(timeProvider); var outbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Mapper_Registry_Async.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Mapper_Registry_Async.cs index e5ba57ac36..0c90011a90 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Mapper_Registry_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Mapper_Registry_Async.cs @@ -73,7 +73,7 @@ public CommandProcessorNoMessageMapperAsyncTests() var tracer = new BrighterTracer(timeProvider); var outbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Producer.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Producer.cs index c258b08f7f..122182f6c9 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Producer.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Producer.cs @@ -75,7 +75,7 @@ public void When_Creating_A_Command_Processor_Without_Producer_Registry() { var policyRegistry = new PolicyRegistry { { CommandProcessor.RETRYPOLICY, _retryPolicy }, { CommandProcessor.CIRCUITBREAKER, _circuitBreakerPolicy } }; - _exception = Catch.Exception(() => new ExternalBusService( + _exception = Catch.Exception(() => new OutboxProducerMediator( null, policyRegistry, _messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Transformer.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Transformer.cs index d78b30c160..6db6d1b8dd 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Transformer.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Transformer.cs @@ -98,7 +98,7 @@ public CommandProcessorPostMissingMessageTransformerTests() [Fact] public void When_Creating_A_Command_Processor_Without_Message_Transformer() { - _exception = Catch.Exception(() => new ExternalBusService( + _exception = Catch.Exception(() => new OutboxProducerMediator( _producerRegistry, _policyRegistry, _messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Transformer_Async.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Transformer_Async.cs index dd772c5ebd..9be61b1b72 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Transformer_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_And_There_Is_No_Message_Transformer_Async.cs @@ -89,7 +89,7 @@ public CommandProcessorPostMissingMessageTransformerTestsAsync() [Fact] public void When_Creating_A_Command_Processor_Without_Message_Transformer_Async() { - _exception = Catch.Exception(() => new ExternalBusService( + _exception = Catch.Exception(() => new OutboxProducerMediator( _producerRegistry, _policyRegistry, _messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_To_The_Command_Processor.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_To_The_Command_Processor.cs index 12ec870e7e..9735e800b3 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_To_The_Command_Processor.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_To_The_Command_Processor.cs @@ -83,7 +83,7 @@ public CommandProcessorPostCommandTests() var tracer = new BrighterTracer(timeProvider); _outbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_To_The_Command_Processor_Async.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_To_The_Command_Processor_Async.cs index 22d35718dd..07ffac48d8 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_To_The_Command_Processor_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_A_Message_To_The_Command_Processor_Async.cs @@ -80,7 +80,7 @@ public CommandProcessorPostCommandAsyncTests() var tracer = new BrighterTracer(timeProvider); _outbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_Fails_Limit_Total_Writes_To_OutBox_In_Window.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_Fails_Limit_Total_Writes_To_OutBox_In_Window.cs index 3859e1aa3a..a81fd1d745 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_Fails_Limit_Total_Writes_To_OutBox_In_Window.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_Fails_Limit_Total_Writes_To_OutBox_In_Window.cs @@ -61,7 +61,7 @@ public PostFailureLimitCommandTests() var producerRegistry = new ProducerRegistry(new Dictionary { { routingKey, producer }, }); - var externalBus = new ExternalBusService( + var externalBus = new OutboxProducerMediator( producerRegistry: producerRegistry, policyRegistry: new DefaultPolicy(), mapperRegistry: messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_Via_A_Control_Bus_Sender.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_Via_A_Control_Bus_Sender.cs index 55add6aa91..0b68ad0c56 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_Via_A_Control_Bus_Sender.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_Via_A_Control_Bus_Sender.cs @@ -81,7 +81,7 @@ public ControlBusSenderPostMessageTests() var tracer = new BrighterTracer(_timeProvider); _outbox = new InMemoryOutbox(_timeProvider) {Tracer = tracer}; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_Via_A_Control_Bus_Sender_Async.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_Via_A_Control_Bus_Sender_Async.cs index 31911f393a..270d247735 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_Via_A_Control_Bus_Sender_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_Via_A_Control_Bus_Sender_Async.cs @@ -78,7 +78,7 @@ public ControlBusSenderPostMessageAsyncTests() var producerRegistry = new ProducerRegistry(new Dictionary {{_routingKey, producer},}); var policyRegistry = new PolicyRegistry { { CommandProcessor.RETRYPOLICYASYNC, retryPolicy }, { CommandProcessor.CIRCUITBREAKERASYNC, circuitBreakerPolicy } }; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_With_A_Default_Policy.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_With_A_Default_Policy.cs index ef101ab4f0..766cddefaf 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_With_A_Default_Policy.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_With_A_Default_Policy.cs @@ -71,7 +71,7 @@ public PostCommandTests() var producerRegistry = new ProducerRegistry(new Dictionary { { _routingKey, producer }, }); - var externalBus = new ExternalBusService( + var externalBus = new OutboxProducerMediator( producerRegistry: producerRegistry, policyRegistry: new DefaultPolicy(), mapperRegistry: messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_With_An_In_Memory_Message_Store.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_With_An_In_Memory_Message_Store.cs index 7ec3639691..dd4225253d 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_With_An_In_Memory_Message_Store.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_With_An_In_Memory_Message_Store.cs @@ -80,7 +80,7 @@ public CommandProcessorWithInMemoryOutboxTests() var tracer = new BrighterTracer(timeProvider); _outbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_With_An_In_Memory_Message_Store_Async.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_With_An_In_Memory_Message_Store_Async.cs index 74877fb72a..a55dc080b6 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_With_An_In_Memory_Message_Store_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Post/When_Posting_With_An_In_Memory_Message_Store_Async.cs @@ -81,7 +81,7 @@ public CommandProcessorWithInMemoryOutboxAscyncTests() var policyRegistry = new PolicyRegistry { { CommandProcessor.RETRYPOLICYASYNC, retryPolicy }, { CommandProcessor.CIRCUITBREAKERASYNC, circuitBreakerPolicy } }; var producerRegistry = new ProducerRegistry(new Dictionary {{_routingKey, producer},}); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/When_A_Request_Context_Is_Provided.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/When_A_Request_Context_Is_Provided.cs index c1c6790bed..ca3ec46ab7 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/When_A_Request_Context_Is_Provided.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/When_A_Request_Context_Is_Provided.cs @@ -170,7 +170,7 @@ public void When_A_Request_Context_Is_Provided_On_A_Deposit() var tracer = new BrighterTracer(timeProvider); var fakeOutbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - var bus = new ExternalBusService( + var bus = new OutboxProducerMediator( producerRegistry, _policyRegistry, messageMapperRegistry, @@ -220,7 +220,7 @@ public async Task When_A_Request_Context_Is_Provided_On_A_Deposit_Async() var tracer = new BrighterTracer(timeProvider); var fakeOutbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - var bus = new ExternalBusService( + var bus = new OutboxProducerMediator( producerRegistry, _policyRegistry, messageMapperRegistry, @@ -270,7 +270,7 @@ public void When_A_Request_Context_Is_Provided_On_A_Clear() var tracer = new BrighterTracer(timeProvider); var fakeOutbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - var bus = new ExternalBusService( + var bus = new OutboxProducerMediator( producerRegistry, _policyRegistry, messageMapperRegistry, @@ -324,7 +324,7 @@ public async Task When_A_Request_Context_Is_Provided_On_A_Clear_Async() var tracer = new BrighterTracer(timeProvider); var fakeOutbox = new InMemoryOutbox(timeProvider); - var bus = new ExternalBusService( + var bus = new OutboxProducerMediator( producerRegistry, _policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/When_No_Request_Context_Is_Provided.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/When_No_Request_Context_Is_Provided.cs index 670f298acb..9b8de7a371 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/When_No_Request_Context_Is_Provided.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/When_No_Request_Context_Is_Provided.cs @@ -141,7 +141,7 @@ public void When_No_Request_Context_Is_Provided_On_A_Deposit() var tracer = new BrighterTracer(); var fakeOutbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - var bus = new ExternalBusService( + var bus = new OutboxProducerMediator( producerRegistry, _policyRegistry, messageMapperRegistry, @@ -187,7 +187,7 @@ public async Task When_No_Request_Context_Is_Provided_On_A_Deposit_Async() var tracer = new BrighterTracer(); var fakeOutbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - var bus = new ExternalBusService( + var bus = new OutboxProducerMediator( producerRegistry, _policyRegistry, messageMapperRegistry, @@ -234,7 +234,7 @@ public void When_No_Request_Context_Is_Provided_On_A_Clear() var tracer = new BrighterTracer(); var fakeOutbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - var bus = new ExternalBusService( + var bus = new OutboxProducerMediator( producerRegistry, _policyRegistry, messageMapperRegistry, @@ -285,7 +285,7 @@ public async Task When_A_Request_Context_Is_Provided_On_A_Clear_Async() var tracer = new BrighterTracer(); var fakeOutbox = new InMemoryOutbox(timeProvider) {Tracer = tracer}; - var bus = new ExternalBusService( + var bus = new OutboxProducerMediator( producerRegistry, _policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs index 24aa6c5d67..e704dc8515 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox.cs @@ -19,7 +19,7 @@ namespace Paramore.Brighter.Core.Tests.Observability.Archive; public class ExternalServiceBusArchiveObservabilityTests { private readonly List _exportedActivities = new(); - private readonly ExternalBusService _bus; + private readonly OutboxProducerMediator _bus; private readonly Publication _publication; private readonly FakeTimeProvider _timeProvider; private RoutingKey _routingKey = new("MyEvent"); @@ -76,7 +76,7 @@ public ExternalServiceBusArchiveObservabilityTests() _archiver = new OutboxArchiver(_outbox, archiveProvider, tracer: tracer); - _bus = new ExternalBusService( + _bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox_async.cs b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox_async.cs index e08326743b..a4caa315d5 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox_async.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/Archive/When_archiving_from_the_outbox_async.cs @@ -21,7 +21,7 @@ namespace Paramore.Brighter.Core.Tests.Observability.Archive; public class AsyncExternalServiceBusArchiveObservabilityTests { private readonly List _exportedActivities = new(); - private readonly ExternalBusService _bus; + private readonly OutboxProducerMediator _bus; private readonly Publication _publication; private readonly FakeTimeProvider _timeProvider; private readonly RoutingKey _routingKey = new("MyEvent"); @@ -78,7 +78,7 @@ public AsyncExternalServiceBusArchiveObservabilityTests() _archiver = new OutboxArchiver(_outbox, archiveProvider, tracer: tracer); - _bus = new ExternalBusService( + _bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported.cs index 4826fc22e5..3656ddae8a 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported.cs @@ -77,7 +77,7 @@ public CommandProcessorClearObservabilityTests() {routingKey, _producer} }); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported_Async.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported_Async.cs index 8cd6011db6..fced18f4a6 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_A_Message_A_Span_Is_Exported_Async.cs @@ -77,7 +77,7 @@ public AsyncCommandProcessorClearObservabilityTests() {_topic, _producer} }); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multipile_Messages_Spans_Are_Exported_Async.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multipile_Messages_Spans_Are_Exported_Async.cs index 3109255448..82f41ccef4 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multipile_Messages_Spans_Are_Exported_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multipile_Messages_Spans_Are_Exported_Async.cs @@ -80,7 +80,7 @@ public AsyncCommandProcessorMultipleClearObservabilityTests() {routingKey, producer} }); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multiple_Messages_Spans_Are_Exported.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multiple_Messages_Spans_Are_Exported.cs index da62fac280..756c6316d9 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multiple_Messages_Spans_Are_Exported.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Multiple_Messages_Spans_Are_Exported.cs @@ -78,7 +78,7 @@ public CommandProcessorMultipleClearObservabilityTests() {routingKey, producer} }); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Outstanding_Messages_Spans_Are_Exported.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Outstanding_Messages_Spans_Are_Exported.cs index 062ecde4bc..bae7b808bb 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Outstanding_Messages_Spans_Are_Exported.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Outstanding_Messages_Spans_Are_Exported.cs @@ -80,7 +80,7 @@ public CommandProcessorClearOutstandingObservabilityTests() {routingKey, producer} }); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Outstanding_Messages_Spans_Are_Exported_Bulk.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Outstanding_Messages_Spans_Are_Exported_Bulk.cs index 51dc6ffc8c..3d36f9b05d 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Outstanding_Messages_Spans_Are_Exported_Bulk.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Clear/When_Clearing_Outstanding_Messages_Spans_Are_Exported_Bulk.cs @@ -79,7 +79,7 @@ public AsyncCommandProcessorBulkClearOutstandingObservabilityTests() {routingKey, producer} }); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_A_Request_A_Span_Is_Exported.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_A_Request_A_Span_Is_Exported.cs index 03f013d2b2..1ad5671dad 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_A_Request_A_Span_Is_Exported.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_A_Request_A_Span_Is_Exported.cs @@ -71,7 +71,7 @@ public CommandProcessorDepositObservabilityTests() } }); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_A_Request_A_Span_Is_Exported_Async.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_A_Request_A_Span_Is_Exported_Async.cs index 5205ef2666..d501b91e83 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_A_Request_A_Span_Is_Exported_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_A_Request_A_Span_Is_Exported_Async.cs @@ -73,7 +73,7 @@ public AsyncCommandProcessorDepositObservabilityTests() } }); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_Multiple_Requests_Spans_Are_Exported.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_Multiple_Requests_Spans_Are_Exported.cs index a610a16e26..4e09ac05b3 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_Multiple_Requests_Spans_Are_Exported.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_Multiple_Requests_Spans_Are_Exported.cs @@ -70,7 +70,7 @@ public CommandProcessorMultipleDepositObservabilityTests() } }); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_Multiple_Requests_Spans_Are_Exported_Async.cs b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_Multiple_Requests_Spans_Are_Exported_Async.cs index 9e9755679b..84fec391b0 100644 --- a/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_Multiple_Requests_Spans_Are_Exported_Async.cs +++ b/tests/Paramore.Brighter.Core.Tests/Observability/CommandProcessor/Deposit/When_Depositing_Multiple_Requests_Spans_Are_Exported_Async.cs @@ -71,7 +71,7 @@ public AsyncCommandProcessorMultipleDepositObservabilityTests() } }); - IAmAnExternalBusService bus = new ExternalBusService( + IAmAnOutboxProducerMediator bus = new OutboxProducerMediator( producerRegistry, policyRegistry, messageMapperRegistry, diff --git a/tests/Paramore.Brighter.InMemory.Tests/Sweeper/When_sweeping_the_outbox.cs b/tests/Paramore.Brighter.InMemory.Tests/Sweeper/When_sweeping_the_outbox.cs index dfb3636599..9d684d1680 100644 --- a/tests/Paramore.Brighter.InMemory.Tests/Sweeper/When_sweeping_the_outbox.cs +++ b/tests/Paramore.Brighter.InMemory.Tests/Sweeper/When_sweeping_the_outbox.cs @@ -52,7 +52,7 @@ public async Task When_outstanding_in_outbox_sweep_clears_them() mapperRegistry.Register(); - var bus = new ExternalBusService( + var bus = new OutboxProducerMediator( producerRegistry, new DefaultPolicy(), mapperRegistry, @@ -128,7 +128,7 @@ public async Task When_outstanding_in_outbox_sweep_clears_them_async() mapperRegistry.Register(); - var bus = new ExternalBusService( + var bus = new OutboxProducerMediator( producerRegistry, new DefaultPolicy(), mapperRegistry, @@ -203,7 +203,7 @@ public async Task When_too_new_to_sweep_leaves_them() mapperRegistry.Register(); - var bus = new ExternalBusService( + var bus = new OutboxProducerMediator( producerRegistry, new DefaultPolicy(), mapperRegistry, @@ -287,7 +287,7 @@ public async Task When_too_new_to_sweep_leaves_them_async() mapperRegistry.Register(); - var bus = new ExternalBusService( + var bus = new OutboxProducerMediator( producerRegistry, new DefaultPolicy(), mapperRegistry, From c8242585e4d5ed4a377463c32d730a1808722133 Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Mon, 28 Oct 2024 11:19:35 +0000 Subject: [PATCH 13/15] fix: name the mediator correctly --- .../ServiceCollectionExtensions.cs | 6 +----- .../ControlBus/ControlBusReceiverBuilder.cs | 4 ++-- src/Paramore.Brighter/ControlBusSenderFactory.cs | 4 ++-- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Paramore.Brighter.Extensions.DependencyInjection/ServiceCollectionExtensions.cs b/src/Paramore.Brighter.Extensions.DependencyInjection/ServiceCollectionExtensions.cs index e20f1776b4..c20e4503eb 100644 --- a/src/Paramore.Brighter.Extensions.DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Paramore.Brighter.Extensions.DependencyInjection/ServiceCollectionExtensions.cs @@ -30,7 +30,6 @@ THE SOFTWARE. */ using Paramore.Brighter.FeatureSwitch; using Paramore.Brighter.Logging; using System.Text.Json; -using System.Transactions; using Paramore.Brighter.DynamoDb; using Paramore.Brighter.Observability; using Polly.Registry; @@ -94,7 +93,7 @@ public static IBrighterBuilder BrighterHandlerBuilder(IServiceCollection service var mapperRegistry = new ServiceCollectionMessageMapperRegistry(services, options.MapperLifetime); services.TryAddSingleton(mapperRegistry); - services.TryAddSingleton(options.RequestContextFactory); + services.TryAddSingleton(options.RequestContextFactory); if (options.FeatureSwitchRegistry != null) services.TryAddSingleton(options.FeatureSwitchRegistry); @@ -136,9 +135,6 @@ public static IBrighterBuilder BrighterHandlerBuilder(IServiceCollection service /// /// The Brighter builder to add this option to /// A callback that allows you to configure options - /// The transaction provider for the outbox, can be null for in-memory default - /// of which you must set the generic type to for - /// /// The lifetime of the transaction provider /// The Brighter builder to allow chaining of requests public static IBrighterBuilder UseExternalBus( diff --git a/src/Paramore.Brighter.ServiceActivator/ControlBus/ControlBusReceiverBuilder.cs b/src/Paramore.Brighter.ServiceActivator/ControlBus/ControlBusReceiverBuilder.cs index a175d10c23..b5d2fe371d 100644 --- a/src/Paramore.Brighter.ServiceActivator/ControlBus/ControlBusReceiverBuilder.cs +++ b/src/Paramore.Brighter.ServiceActivator/ControlBus/ControlBusReceiverBuilder.cs @@ -158,7 +158,7 @@ public Dispatcher Build(string hostName) var outbox = new SinkOutboxSync(); - var externalBus = new OutboxProducerMediator( + var mediator = new OutboxProducerMediator( producerRegistry: producerRegistry, policyRegistry: new DefaultPolicy(), mapperRegistry: outgoingMessageMapperRegistry, @@ -175,7 +175,7 @@ public Dispatcher Build(string hostName) commandProcessor = CommandProcessorBuilder.StartNew() .Handlers(new HandlerConfiguration(subscriberRegistry, new ControlBusHandlerFactorySync(_dispatcher, () => commandProcessor))) .Policies(policyRegistry) - .ExternalBus(ExternalBusType.FireAndForget, externalBus) + .ExternalBus(ExternalBusType.FireAndForget, mediator) .ConfigureInstrumentation(null, InstrumentationOptions.None) .RequestContextFactory(new InMemoryRequestContextFactory()) .Build(); diff --git a/src/Paramore.Brighter/ControlBusSenderFactory.cs b/src/Paramore.Brighter/ControlBusSenderFactory.cs index 5e02c9064f..20d9317f29 100644 --- a/src/Paramore.Brighter/ControlBusSenderFactory.cs +++ b/src/Paramore.Brighter/ControlBusSenderFactory.cs @@ -49,7 +49,7 @@ public IAmAControlBusSender Create(IAmAnOutbox outbox, IAmAProd null); mapper.Register(); - var bus = new OutboxProducerMediator( + var mediator = new OutboxProducerMediator( producerRegistry: producerRegistry, policyRegistry: new DefaultPolicy(), mapperRegistry: mapper, @@ -62,7 +62,7 @@ public IAmAControlBusSender Create(IAmAnOutbox outbox, IAmAProd CommandProcessorBuilder.StartNew() .Handlers(new HandlerConfiguration()) .DefaultPolicy() - .ExternalBus(ExternalBusType.FireAndForget, bus) + .ExternalBus(ExternalBusType.FireAndForget, mediator) .ConfigureInstrumentation(null, InstrumentationOptions.None) .RequestContextFactory(new InMemoryRequestContextFactory()) .Build() From 513052d101bde5535a75e2a48ed93ac61d3327ee Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Mon, 28 Oct 2024 12:10:15 +0000 Subject: [PATCH 14/15] fix: issue with PackageReference not PackageVersion --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 53f0a82a43..cebcdb974c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -54,7 +54,7 @@ - + From 8890035310cabc9fa482d0deef5d3cac70c21615 Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Mon, 28 Oct 2024 17:35:28 +0000 Subject: [PATCH 15/15] fix: failing reflection based construction of OutBoxProducerMediator due to additional parameters --- .../ServiceCollectionExtensions.cs | 6 ++---- ..._A_Server_Via_The_Command_Processor_With_No_In_Mapper.cs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Paramore.Brighter.Extensions.DependencyInjection/ServiceCollectionExtensions.cs b/src/Paramore.Brighter.Extensions.DependencyInjection/ServiceCollectionExtensions.cs index c20e4503eb..30acbb9e21 100644 --- a/src/Paramore.Brighter.Extensions.DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Paramore.Brighter.Extensions.DependencyInjection/ServiceCollectionExtensions.cs @@ -219,7 +219,7 @@ public static IBrighterBuilder UseExternalBus( brighterBuilder.Services.TryAddSingleton(busConfiguration); brighterBuilder.Services.TryAdd(new ServiceDescriptor(typeof(IAmAnOutboxProducerMediator), - (serviceProvider) => BuildExternalBus( + (serviceProvider) => BuildOutBoxProducerMediator( serviceProvider, transactionType, busConfiguration, brighterBuilder.PolicyRegistry, outbox ), ServiceLifetime.Singleton)); @@ -321,7 +321,7 @@ private static object BuildCommandProcessor(IServiceProvider provider) return commandProcessor; } - private static IAmAnOutboxProducerMediator BuildExternalBus(IServiceProvider serviceProvider, + private static IAmAnOutboxProducerMediator BuildOutBoxProducerMediator(IServiceProvider serviceProvider, Type transactionType, ExternalBusConfiguration busConfiguration, IPolicyRegistry policyRegistry, @@ -340,13 +340,11 @@ private static IAmAnOutboxProducerMediator BuildExternalBus(IServiceProvider ser TransformFactoryAsync(serviceProvider), Tracer(serviceProvider), outbox, - busConfiguration.ArchiveProvider, RequestContextFactory(serviceProvider), busConfiguration.OutboxTimeout, busConfiguration.MaxOutStandingMessages, busConfiguration.MaxOutStandingCheckInterval, busConfiguration.OutBoxBag, - busConfiguration.ArchiveBatchSize, TimeProvider.System, busConfiguration.InstrumentationOptions); } diff --git a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_In_Mapper.cs b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_In_Mapper.cs index 7d55d51c70..2f9058f97d 100644 --- a/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_In_Mapper.cs +++ b/tests/Paramore.Brighter.Core.Tests/CommandProcessors/Call/When_Calling_A_Server_Via_The_Command_Processor_With_No_In_Mapper.cs @@ -93,7 +93,7 @@ public void When_Calling_A_Server_Via_The_Command_Processor_With_No_Out_Mapper() var exception = Catch.Exception(() => _commandProcessor.Call(_myRequest, new RequestContext(), TimeSpan.FromMilliseconds(500))); //should throw an exception as we require a mapper for the outgoing request - exception.Should().BeOfType(); + exception.Should().BeOfType(); } public void Dispose()