From 1afea2edf34557f105617ed537aa7c4fc5635f9a Mon Sep 17 00:00:00 2001 From: Frank Chen <65260095+zhongkechen@users.noreply.github.com> Date: Thu, 6 Aug 2026 14:02:27 -0700 Subject: [PATCH] fix(otel): keep continuation spans within invocation --- .../durable/otel/InvocationOtelPlugin.java | 4 ---- .../otel/InvocationOtelPluginTest.java | 20 +++++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/otel-plugin/src/main/java/software/amazon/lambda/durable/otel/InvocationOtelPlugin.java b/otel-plugin/src/main/java/software/amazon/lambda/durable/otel/InvocationOtelPlugin.java index 07dd19e66..227542d8a 100644 --- a/otel-plugin/src/main/java/software/amazon/lambda/durable/otel/InvocationOtelPlugin.java +++ b/otel-plugin/src/main/java/software/amazon/lambda/durable/otel/InvocationOtelPlugin.java @@ -453,10 +453,6 @@ public void onOperationEnd(OperationEndInfo info) { .setAttribute(DURABLE_OPERATION_TYPE, info.type()); addWorkflowLink(spanBuilder); - if (info.startTimestamp() != null) { - spanBuilder.setStartTimestamp(info.startTimestamp()); - } - if (info.name() != null) { spanBuilder.setAttribute(DURABLE_OPERATION_NAME, info.name()); } diff --git a/otel-plugin/src/test/java/software/amazon/lambda/durable/otel/InvocationOtelPluginTest.java b/otel-plugin/src/test/java/software/amazon/lambda/durable/otel/InvocationOtelPluginTest.java index 018273260..020e3cbbe 100644 --- a/otel-plugin/src/test/java/software/amazon/lambda/durable/otel/InvocationOtelPluginTest.java +++ b/otel-plugin/src/test/java/software/amazon/lambda/durable/otel/InvocationOtelPluginTest.java @@ -914,11 +914,11 @@ void operationEnd_withoutMatchingStart_createsContinuationSpanWithLink() { } @Test - void operationEnd_withoutMatchingStart_usesOperationStartTimestamp() { + void operationEnd_withoutMatchingStart_startsWithinCurrentInvocation() { plugin.onInvocationStart(new InvocationInfo("req-1", "arn:exec1", true, Instant.now())); - var operationStart = Instant.parse("2026-01-15T08:30:00Z"); - var operationEnd = Instant.parse("2026-01-15T09:00:00Z"); + var operationStart = Instant.EPOCH; + var operationEnd = operationStart.plusSeconds(60); // onOperationEnd without a prior onOperationStart — continuation span plugin.onOperationEnd(new OperationEndInfo( @@ -936,15 +936,19 @@ void operationEnd_withoutMatchingStart_usesOperationStartTimestamp() { plugin.onInvocationEnd(new InvocationEndInfo("req-1", "arn:exec1", true, InvocationStatus.SUCCEEDED, null)); - var continuationSpan = spanExporter.getFinishedSpanItems().stream() + var spans = spanExporter.getFinishedSpanItems(); + var continuationSpan = spans.stream() .filter(s -> s.getName().contains("wait")) .findFirst() .orElseThrow(); + var invocationSpan = spans.stream() + .filter(s -> s.getName().equals("Invocation")) + .findFirst() + .orElseThrow(); - assertEquals( - operationStart.toEpochMilli(), - continuationSpan.getStartEpochNanos() / 1_000_000, - "Continuation span should use the operation's startTimestamp"); + assertEquals(invocationSpan.getSpanId(), continuationSpan.getParentSpanId()); + assertTrue(continuationSpan.getStartEpochNanos() >= invocationSpan.getStartEpochNanos()); + assertTrue(continuationSpan.getEndEpochNanos() <= invocationSpan.getEndEpochNanos()); } @Test