[Bug]: OTel re-exports already completed STEP spans after invocation retry
Maintainer antworten meist innerhalb von 1 Tag
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Anfängerfreundlichkeit
- 42/100
- Issue-Typ
- Bug
- Klarheit
- Klar beschrieben
- Aktivitätsstatus
- Aktiv
- Tech-Stack
- python
- Bereich
- observability
Rechercherichtung
Trace how UpdatedOperationIds reaches the update hook in packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/context.py and how terminal updates become OperationEndInfo in plugin.py. Then compare replay handling in the OTel execution_plugin.py with both configured views and identify existing tests to extend. Done means terminal STEP replay is suppressed in both views while real step and attempt telemetry, invocation outcomes, and non-STEP completion delivery remain intact.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Expected Behavior
Replaying an already checkpointed terminal STEP must not trigger another SDK-generated operation or attempt span in either OTel view. Span delivery remains best-effort.
Apply this without persisting spans or export acknowledgements, adding checkpoint operations, or changing stored operation results.
Actual Behavior
When Lambda retries an invocation that failed after a step was successfully checkpointed, the Python Execution view can export that completed step again with the same trace/span ID but different timestamps. The step body is correctly skipped. The second span represents reconstruction from checkpoint history, not another step execution.
The requested fix is best-effort suppression of terminal STEP replay telemetry. It does not require persistent span storage or claim exactly-once telemetry delivery.
Steps to Reproduce and Evidence
Verified on AWS Lambda Python 3.13 using Python SDK 3.0.1 and OTel 2.0.0 from commit 4625d01b. A real in-memory OTel exporter captured spans before any external collector could deduplicate them. An outer wrapper recorded allowlisted fields from the actual Lambda invocation input without modifying it.
| Scenario | Actual subsequent UpdatedOperationIds |
Observed Execution-view STEP spans |
|---|---|---|
Step A succeeds; handler raises public InvocationError; Lambda retries |
Execution operation and completed A | Same trace/span ID twice: 120.921344 ms, then 0.000768 ms |
| A succeeds; a durable wait suspends normally; Lambda resumes | Only the completed wait | A exported once |
A succeeds; wait suspends normally; resume runs B; handler raises InvocationError; Lambda retries |
Resume: wait. Retry: wait and completed B, excluding A | A exported once. B reused its trace/span ID: 75.184128 ms, then 0.000768 ms |
Each scenario was run in both Execution and Invocation views: six successful durable executions and fourteen Lambda invocations. Every step body ran once; execution history contained one StepStarted and one StepSucceeded per step. All invocation request IDs matched history, and all input and span-completion records were present. Invocation view produced distinct span IDs for its additional segments; it did not exhibit the same span-identity collision.
These are new cloud measurements, not the exact durations of the original report. The probe used an explicit provider, in-memory exporter, and no incoming trace-context extractor, so it verifies the SDK/plugin lifecycle independently of the original collector configuration. FAILED checkpoint replay was not exercised by this cloud run and needs regression coverage.
Why the existing replay check misses this
In the verified revision:
DurableContextroutes an operation inUpdatedOperationIdsthrough the update hook, even when its STEP checkpoint is already terminal on invocation entry.- The terminal update is converted into
OperationEndInfowithis_replayed=False. Checking only that flag therefore does not identify this case. - Execution-view deduplication is invocation-local, and span timing incorporates the current invocation's placeholder when present. The retry has no original attempt timing. Its recorded checkpoint start/end were equal in these runs, while the first export included the actual attempt interval.
Requested behavior
Distinguish a STEP that was already terminal in the invocation's checkpoint input/history from a STEP that actually executes or reaches a terminal state in this invocation. Do not export an additional logical STEP span merely because the former is encountered through UpdatedOperationIds. Apply that suppression in both bundled OTel views: Invocation view currently avoids a span-ID collision by creating a new segment, but that segment still represents a cached terminal step rather than new work.
The implementation may live at the core/plugin boundary or in OTel handling. Use the operation's provenance/already-terminal-on-entry state, not a blanket check of its current terminal status: a step that just completed in this invocation still needs its span. Do not delete generic plugin terminal-update notifications merely to suppress OTel replay spans.
Acceptance criteria
- A STEP already in
SUCCEEDEDorFAILEDin invocation input/history must not produce another logical STEP operation span, or a synthetic step-attempt span, solely because it is replayed throughUpdatedOperationIds. Cover both a listed ID and the ordinary replay path, in both OTel views. - Apply that decision by operation type
STEP, regardless of subtype. Include a non-default/custom STEP subtype regression, rather than filtering onlysub_type == "Step". - Preserve replay behavior: a succeeded step returns its stored value; a failed step reproduces its stored failure; neither executes its body again. The telemetry change must not alter checkpoint contents or operation identity.
- Preserve telemetry for actual work: a new step, a real retry attempt of a nonterminal step, and a terminal checkpoint first produced by that attempt still emit their normal operation/attempt telemetry. Include a retry/resume regression that would fail if all replayed or pre-existing STEP IDs were suppressed.
- Keep invocation spans and invocation outcomes accurate. Test both configured views so a shared-hook change does not silently remove actual invocation or retry-attempt telemetry.
- Do not globally filter terminal operations from
UpdatedOperationIds. WAIT, CHAINED_INVOKE, and CALLBACK completion delivery must continue to work, including completions first observed on resume. Include focused non-STEP regression coverage. - Cover the three-invocation control: A -> wait/PENDING -> B -> invocation failure -> retry. A and B execute once each; terminal replay does not reconstruct another STEP span; the completed wait still reaches its normal completion handling.
- Implement and document this as best-effort replay suppression without persisting spans or export acknowledgements in durable checkpoints.
Related work
- #854 concerns discovering/delivering replay-visible completions. Preserve its handling of externally completed operations. This issue targets already-terminal STEP history, not all replay-visible updates.
- #855 concerns invocation-local export retry. Bounded retry of an export being delivered within the current invocation remains compatible with this change. Suppress reconstruction from a later invocation's terminal STEP history, not retry of a current invocation's live completion export.
Remaining limitation
The original expectation, “export once, or make every copy identical,” is stronger than this fix can guarantee without durable telemetry state. Step checkpointing and span export are separate actions. If an invocation ends after the step checkpoint succeeds but before its span is exported, suppressing terminal replay may leave that step without a span. Re-exporting instead cannot reliably recreate the original local attempt timestamps, attributes, or events from the operation checkpoint alone. Export transports can also deliver duplicate batches.
The bounded objective is therefore to stop avoidable reconstruction of already-terminal STEP spans during replay, while retaining real execution telemetry. It is not a promise of exactly-once export, lossless recovery after interruption, or byte-identical copies across failures.
SDK Version / Python Version
Core 3.0.1 and OTel 2.0.0, source 4625d01bbfa97da67050014851af7eb41c61a842; Lambda Python 3.13. This was still the default branch revision when checked on 2026-10-30.
Is this a regression?
Unknown. No working version was established.
Companion Java implementation: https://github.com/aws/aws-durable-execution-sdk-java/issues/857.
- Vorherrschende Sprache
- Python
- Sterne
- 58
- Forks
- 32
- Ø Merge
- 1 T. 6 Std.
- Gemergte PRs (30 T.)
- 80
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Hat eine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus aws/aws-durable-execution-sdk-python
-
enhancement needs-triage
Schwierigkeit 1/5 1-3 Stunden Anfängerfreundlichkeit 72/100
aws/aws-durable-execution-sdk-python#927 ·
Maintainer antworten meist innerhalb von 1 Tag
-
enhancement
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
aws/aws-durable-execution-sdk-python#875 ·
Maintainer antworten meist innerhalb von 1 Tag
-
enhancement
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 85/100
aws/aws-durable-execution-sdk-python#794 ·
Maintainer antworten meist innerhalb von 1 Tag
-
bug
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 58/100
aws/aws-durable-execution-sdk-python#921 ·
Maintainer antworten meist innerhalb von 1 Tag
-
[Bug]: JS examples CI still invokes Jest after Vitest migrationEvtl. vergeben Ein verknüpfter Pull Request ist offen oder bereits gemergt. Offenbug needs-triage
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 55/100
aws/aws-durable-execution-sdk-python#918 ·
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in aws/aws-durable-execution-sdk-python
Ähnliche Issues
-
physical
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 74/100
antonyrag/ragleap-core#1339 ·
-
enhancement good first issue
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 83/100
AllenCell/SubCellSeg#5 ·
-
[🐛 Bug]: oidc_authverifier.py strips trailing slash causing "Invalid token: Invalid issuer" errorOffen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 76/100
keephq/keep#6934 · 1 Reaktion ·
Maintainer antworten meist innerhalb von 1 Tag
-
bug game: 01008BA02525A000 ios
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 76/100
Maintainer antworten meist innerhalb von 1 Tag
-
needs-triage
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 87/100
gke-labs/kube-agents#5501 ·
Maintainer antworten meist innerhalb von 1 Tag