From 71f0aa03a8720f207dc9aff206c32c76a80d04c1 Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Fri, 17 Jul 2026 22:26:39 +0100 Subject: [PATCH] fix(telemetry): detach InboundLedger acquire span (created and reset on different threads) acquireSpan_ is emplaced on the acquiring caller thread but reset() in done() on a JtLedgerData worker. Detaching strips the thread-local OTel Scope on the origin thread so destruction on the worker does not corrupt the origin thread's context stack. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/xrpld/app/ledger/InboundLedger.h | 4 ++++ src/xrpld/app/ledger/detail/InboundLedger.cpp | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/xrpld/app/ledger/InboundLedger.h b/src/xrpld/app/ledger/InboundLedger.h index 48f73d6781..9465eb480d 100644 --- a/src/xrpld/app/ledger/InboundLedger.h +++ b/src/xrpld/app/ledger/InboundLedger.h @@ -194,6 +194,10 @@ private: /// with the outcome (complete/failed), timeout count, and peer count. /// Gives operators visibility into back-fill / fork-recovery cost, which /// previously emitted no span or metric. + /// Stored detached: emplaced by the acquiring thread, reset on a + /// JtLedgerData worker. detached() strips the thread-local Scope so the + /// guard can be destroyed on the worker without corrupting the origin + /// thread's context stack. std::optional acquireSpan_; }; diff --git a/src/xrpld/app/ledger/detail/InboundLedger.cpp b/src/xrpld/app/ledger/detail/InboundLedger.cpp index 45c2d4d462..1f7283233b 100644 --- a/src/xrpld/app/ledger/detail/InboundLedger.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedger.cpp @@ -103,8 +103,12 @@ InboundLedger::init(ScopedLockType& collectionLock) // observable. Finalized in done() with the outcome and timeout count. { using namespace telemetry; + // Detach the Scope: this guard is emplaced here but reset() on a + // JtLedgerData worker thread. Detaching strips the thread-local Scope + // so its destruction there does not corrupt this thread's context stack. acquireSpan_.emplace( - SpanGuard::span(TraceCategory::Ledger, seg::ledger, ledger_span::op::acquire)); + SpanGuard::span(TraceCategory::Ledger, seg::ledger, ledger_span::op::acquire) + .detached()); if (*acquireSpan_) { acquireSpan_->setAttribute(ledger_span::attr::ledgerSeq, static_cast(seq_));