diff --git a/src/NServiceBus.AcceptanceTests/Core/OpenTelemetry/Traces/When_incoming_message_was_delayed.cs b/src/NServiceBus.AcceptanceTests/Core/OpenTelemetry/Traces/When_incoming_message_was_delayed.cs index 6fa69c676f0..a5319e3469e 100644 --- a/src/NServiceBus.AcceptanceTests/Core/OpenTelemetry/Traces/When_incoming_message_was_delayed.cs +++ b/src/NServiceBus.AcceptanceTests/Core/OpenTelemetry/Traces/When_incoming_message_was_delayed.cs @@ -11,6 +11,24 @@ public class When_incoming_message_was_delayed : OpenTelemetryAcceptanceTest // assuming W3C trace! { + [Test] + public async Task By_sendoptions_Should_create_new_trace_and_set_current_activity() + { + var context = await Scenario.Define() + .WithEndpoint(b => b + .When(s => + { + var sendOptions = new SendOptions(); + sendOptions.DelayDeliveryWith(TimeSpan.FromMilliseconds(100)); + sendOptions.RouteToThisEndpoint(); + return s.Send(new DelayedMessage(), sendOptions); + })) + .Done(c => c.DelayedMessageReceived) + .Run(); + + Assert.That(context.DelayedMessageCurrentActivityId, Is.Not.Null, "delayed message current activityId is not null"); + } + [Test] public async Task By_sendoptions_Should_create_new_trace_and_link_to_send() { @@ -141,6 +159,10 @@ class Context : ScenarioContext public string IncomingMessageId { get; set; } public string ReplyMessageId { get; set; } public bool IncomingMessageReceived { get; set; } + public bool DelayedMessageReceived { get; set; } +#nullable enable + public string? DelayedMessageCurrentActivityId { get; set; } +#nullable disable } class SagaContext : ScenarioContext { @@ -162,6 +184,7 @@ public Task Handle(IncomingMessage message, IMessageHandlerContext context) { testContext.IncomingMessageId = context.MessageId; testContext.IncomingMessageReceived = true; + //testContext.IncomingMessageCurrentActivityId = Activity.Current?.Id; return context.Reply(new ReplyMessage()); } } @@ -198,6 +221,20 @@ public Task Handle(ReplyMessage message, IMessageHandlerContext context) return Task.CompletedTask; } } + + class DelayedMessageHandler : IHandleMessages + { + Context testContext; + + public DelayedMessageHandler(Context testContext) => this.testContext = testContext; + + public Task Handle(DelayedMessage message, IMessageHandlerContext context) + { + testContext.DelayedMessageReceived = true; + testContext.DelayedMessageCurrentActivityId = Activity.Current?.Id; + return Task.CompletedTask; + } + } } class SagaOtelEndpoint : EndpointConfigurationBuilder @@ -286,6 +323,10 @@ public class MessageToBeRetried : IMessage { } + public class DelayedMessage : IMessage + { + } + public class IncomingMessage : IMessage { } diff --git a/src/NServiceBus.Core/OpenTelemetry/Tracing/ActivityFactory.cs b/src/NServiceBus.Core/OpenTelemetry/Tracing/ActivityFactory.cs index a192bad2afb..f2be91499a6 100644 --- a/src/NServiceBus.Core/OpenTelemetry/Tracing/ActivityFactory.cs +++ b/src/NServiceBus.Core/OpenTelemetry/Tracing/ActivityFactory.cs @@ -35,7 +35,9 @@ public Activity StartIncomingPipelineActivity(MessageContext context) { // create a new trace or root activity ActivityLink[] links = [new ActivityLink(sendSpanContext)]; - activity = ActivitySources.Main.StartActivity(name: ActivityNames.IncomingMessageActivityName, ActivityKind.Consumer, CreateNewRootActivityContext(), tags: null, links: links); + //null the current activity so that the new one is created as root https://github.com/dotnet/runtime/issues/65528#issuecomment-2613486896 + Activity.Current = null; + activity = ActivitySources.Main.StartActivity(name: ActivityNames.IncomingMessageActivityName, ActivityKind.Consumer, parentContext: default, tags: null, links: links); } else { @@ -66,11 +68,6 @@ public Activity StartIncomingPipelineActivity(MessageContext context) return activity; } - /// - /// This could be cleaned up once a dedicated API is created, see https://github.com/dotnet/runtime/issues/65528 - /// - static ActivityContext CreateNewRootActivityContext() => new(Activity.TraceIdGenerator is null ? ActivityTraceId.CreateRandom() : Activity.TraceIdGenerator(), default, default, default); - public Activity StartOutgoingPipelineActivity(string activityName, string displayName, IBehaviorContext outgoingContext) { var activity = ActivitySources.Main.CreateActivity(activityName, ActivityKind.Producer);