From 4e9b2f8b3454996d7b9035a8a0c41d35b25b9cc9 Mon Sep 17 00:00:00 2001 From: Jo Palac Date: Mon, 20 Jan 2025 15:52:37 +1000 Subject: [PATCH 1/3] Add test for null activity --- .../When_incoming_message_was_delayed.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) 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..5db260bb581 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 @@ -1,4 +1,5 @@ namespace NServiceBus.AcceptanceTests.Core.OpenTelemetry.Traces; +#nullable enable using System; using System.Diagnostics; @@ -11,6 +12,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 +160,8 @@ class Context : ScenarioContext public string IncomingMessageId { get; set; } public string ReplyMessageId { get; set; } public bool IncomingMessageReceived { get; set; } + public bool DelayedMessageReceived { get; set; } + public string? DelayedMessageCurrentActivityId { get; set; } } class SagaContext : ScenarioContext { @@ -162,6 +183,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 +220,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 +322,10 @@ public class MessageToBeRetried : IMessage { } + public class DelayedMessage : IMessage + { + } + public class IncomingMessage : IMessage { } From 41add3277ec6192d06af4302caf60feed5625847 Mon Sep 17 00:00:00 2001 From: Jo Palac Date: Mon, 20 Jan 2025 16:04:19 +1000 Subject: [PATCH 2/3] fix nullable --- .../OpenTelemetry/Traces/When_incoming_message_was_delayed.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 5db260bb581..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 @@ -1,5 +1,4 @@ namespace NServiceBus.AcceptanceTests.Core.OpenTelemetry.Traces; -#nullable enable using System; using System.Diagnostics; @@ -161,7 +160,9 @@ class Context : ScenarioContext 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 { From 74b044683156ef608294ab3584639425ea9ee3a7 Mon Sep 17 00:00:00 2001 From: Jo Palac Date: Tue, 21 Jan 2025 10:21:17 +1000 Subject: [PATCH 3/3] Pass in traceFlags when creating a new root activity from the current context --- .../OpenTelemetry/Tracing/ActivityFactory.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NServiceBus.Core/OpenTelemetry/Tracing/ActivityFactory.cs b/src/NServiceBus.Core/OpenTelemetry/Tracing/ActivityFactory.cs index a192bad2afb..7c2073c8072 100644 --- a/src/NServiceBus.Core/OpenTelemetry/Tracing/ActivityFactory.cs +++ b/src/NServiceBus.Core/OpenTelemetry/Tracing/ActivityFactory.cs @@ -35,7 +35,8 @@ 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); + //pass in traceFlags of current activity, otherwise the activity returned is null + activity = ActivitySources.Main.StartActivity(name: ActivityNames.IncomingMessageActivityName, ActivityKind.Consumer, CreateNewRootActivityContext(sendSpanContext.TraceFlags), tags: null, links: links); } else { @@ -69,7 +70,7 @@ public Activity StartIncomingPipelineActivity(MessageContext context) /// /// 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); + static ActivityContext CreateNewRootActivityContext(ActivityTraceFlags traceFlags) => new(Activity.TraceIdGenerator is null ? ActivityTraceId.CreateRandom() : Activity.TraceIdGenerator(), default, traceFlags, default); public Activity StartOutgoingPipelineActivity(string activityName, string displayName, IBehaviorContext outgoingContext) {