Skip to content

chore(tracer): tracer/writer identity refresh and stale-buffer reset - #19820

Open
litianningdatadog wants to merge 1 commit into
tianning.li/3-wsgi-asgi-integration-based-refreshfrom
tianning.li/3-3-trace-writer-identity-refresh
Open

litianningdatadog wants to merge 1 commit into
tianning.li/3-wsgi-asgi-integration-based-refreshfrom
tianning.li/3-3-trace-writer-identity-refresh

Conversation

@litianningdatadog

@litianningdatadog litianningdatadog commented Aug 23, 2026 •

Copy link
Copy Markdown
Contributor

An explicit AWS Lambda MicroVM identity refresh changes the runtime ID, but the tracer can still hold trace aggregation state and writer-buffered entities created under the previous identity. The native exporter also captures the runtime ID when it is built.

This change wires the global tracer to the explicit identity-refresh notification. On refresh, the tracer:

  • Recreates the span aggregator writer so native exporters capture the current runtime ID.
  • Drops writer-buffered entities and clears active trace aggregation state from the previous identity.
  • Serializes the MicroVM writer transition with span completion and invalidates in-flight traces captured under the old identity generation.
  • Stamps the identity generation on a span when it starts, under the same transition lock used to advance the generation, so a span created just before a refresh cannot slip into the replacement buffer after the transition completes.
  • Rechecks the identity generation before every trace processor runs, not only once before the chain, so a refresh that lands mid-chain stops LLM Observability and CI Visibility span forwarding from publishing an invalidated trace.
  • Detaches the previous request's active local span or context on refresh so a new request's root span is not parented to stale trace state. A context extracted from real distributed-tracing headers on the new request is left active.
  • Stops the previous CIVisibilityWriter before installing its replacement during the transition, and drops the native exporter's pending stats through its non-flushing drop() path instead of a flushing shutdown, so the transition neither leaks a periodic writer thread nor exports stale native metrics.
  • Supports CI Visibility encoders that clear through encode() rather than exposing get().
  • Clears pending post-fork writer recreation after a successful refresh while preserving inherited-process state. Failed recreation leaves the pending flag set for retry.

The refresh callback is registered only for explicit MicroVM identity refresh. The identity-transition lock is enabled only for aggregators initialized in MicroVM mode; normal configuration and post-fork recreation paths retain their existing behavior.

The stale-buffer reset previously proposed in #20089 is included here because it is part of the tracer and writer identity-refresh behavior.

Reference

Testing

Added focused coverage for:

  • Global tracer notification on explicit identity refresh.
  • Current runtime ID propagation into the rebuilt native exporter.
  • Exporter recreation without fork-side effects.
  • CI Visibility and standard writer buffer disposal.
  • Serializing buffer disposal with concurrent NativeWriter writes and flushes.
  • Preventing in-flight old-runtime traces from reaching the replacement writer.
  • Clearing trace aggregation state during identity refresh.
  • Clearing pending post-fork recreation after successful refresh and preserving it after refresh failure.
  • Rejecting a trace mid-chain, before any side-effecting processor (LLM Observability, CI Visibility forwarding) runs, once a refresh invalidates its generation.
  • Detaching the pre-refresh active local span/context on refresh while preserving a remote (distributed-header) context.
  • Stopping the previous CI Visibility writer during a MicroVM refresh instead of leaking its periodic thread.
  • Dropping the native exporter's pending stats via its non-flushing path during a MicroVM refresh, instead of flushing them through a normal shutdown.
  • Non-MicroVM post-fork and aggregator reset behavior.

Validation completed:

  • 50 affected tracer tests passed in the targeted selection.
  • The added refresh-failure regression passed separately.
  • Re-ran tests/tracer/runtime/test_runtime_id.py and tests/tracer/test_writer.py after the latest round of fixes: 185 passed, 10 skipped, 1 xpassed, 0 failed.
  • Style, typing, security, and diff checks passed.

Risks

Pre-refresh trace data is intentionally discarded during explicit MicroVM identity refresh so it cannot be exported with a stale runtime ID. The transition-specific locking is limited to MicroVM identity-refresh state; standard non-MicroVM reset and post-fork paths remain unchanged.

@litianningdatadog litianningdatadog added changelog/no-changelog A changelog entry is not required for this PR. aws-microvm Work related to AWS MicroVM onboarding labels Aug 23, 2026
@litianningdatadog litianningdatadog changed the title fix(tracer): rebuild native writer exporter on identity refresh chore(tracer): rebuild native writer exporter on identity refresh Aug 23, 2026
@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Aug 23, 2026 •

Copy link
Copy Markdown
Contributor

Pipelines  Tests

❌ Errors

Your PR has failed checks. Please review the issues below and take necessary action before merging.

🚦 3 Pipeline jobs failed

DataDog/apm-reliability/dd-trace-py | contrib/molten 2/2 — 🔄 Retry may pass, looks flaky

View more details · View in GitLab

System Tests | serverless-system-tests / Build end-to-end (apigw-rest)

View more details · View in GitHub Actions

System Tests | system-tests finished

View more details · View in GitHub Actions

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 3cda934 | Docs | View more details | Give us feedback!

@pr-commenter

pr-commenter Bot commented Aug 23, 2026 •

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-09-27 04:13:40

Comparing candidate commit 3cda934 in PR branch tianning.li/3-3-trace-writer-identity-refresh with baseline commit 3bb8821 in branch tianning.li/3-wsgi-asgi-integration-based-refresh.

📊 Benchmarking dashboard

Found 0 performance improvements and 8 performance regressions! Performance is the same for 553 metrics, 10 unstable metrics, 7 known flaky benchmarks, 17 flaky benchmarks without significant changes.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:httppropagationextract-empty_headers

  • 🟥 execution_time [+96.554ns; +114.339ns] or [+13.109%; +15.524%]

scenario:iastaspects-add_aspect

  • 🟥 execution_time [+8.506µs; +10.157µs] or [+10.094%; +12.053%]

scenario:iastaspects-format_map_noaspect

  • 🟥 execution_time [+101.136µs; +106.269µs] or [+28.847%; +30.311%]

scenario:iastaspects-title_aspect

  • 🟥 execution_time [+101.195µs; +104.471µs] or [+37.215%; +38.419%]

scenario:iastaspectsremodule-re_expand_aspect

  • 🟥 execution_time [+86.077µs; +100.891µs] or [+13.689%; +16.045%]

scenario:msgpackencoderscenario-simple_one_span

  • 🟥 execution_time [+485.820ns; +547.076ns] or [+11.861%; +13.356%]

scenario:otelspan-start

  • 🟥 execution_time [+2.268ms; +3.087ms] or [+9.252%; +12.590%]

scenario:recursivecomputation-shallow

  • 🟥 execution_time [+54.263µs; +59.370µs] or [+7.739%; +8.467%]

Unstable benchmarks

These benchmarks have a confidence interval too wide to call a change; treat them as noise rather than signal.

scenario:coreapiscenario-context_with_data_listeners

  • unstable execution_time [-716.764ns; +756.021ns] or [-6.903%; +7.281%]

scenario:coreapiscenario-core_dispatch_1_listener

  • unstable execution_time [-34.450ns; +44.226ns] or [-5.206%; +6.683%]

scenario:coreapiscenario-core_dispatch_50_listeners

  • unstable execution_time [-1948.557ns; +1883.382ns] or [-9.798%; +9.470%]

scenario:coreapiscenario-core_dispatch_exception_listeners

  • unstable execution_time [-1817.070ns; +1850.558ns] or [-9.507%; +9.683%]

scenario:coreapiscenario-core_dispatch_listeners

  • unstable execution_time [-388.684ns; +375.930ns] or [-9.146%; +8.846%]

scenario:coreapiscenario-core_dispatch_no_args_listeners

  • unstable execution_time [-239.249ns; +220.584ns] or [-8.948%; +8.249%]

scenario:coreapiscenario-core_dispatch_with_results_1_listener

  • unstable execution_time [-116.495ns; +70.633ns] or [-8.546%; +5.182%]

scenario:coreapiscenario-core_dispatch_with_results_50_listeners

  • unstable execution_time [-4911.756ns; +4325.171ns] or [-10.215%; +8.995%]

scenario:coreapiscenario-core_dispatch_with_results_listeners

  • unstable execution_time [-1009.847ns; +874.908ns] or [-9.926%; +8.600%]

scenario:packagesupdateimporteddependencies-import_many_stdlib_cached

  • unstable execution_time [-54214.204ns; +55321.489ns] or [-9.610%; +9.806%]

Known flaky benchmarks

These benchmarks are marked as flaky and will not trigger a failure. Modify FLAKY_BENCHMARKS_REGEX to control which benchmarks are marked as flaky.

scenario:httppropagationinject-ids_only

  • 🟥 execution_time [+2.817µs; +2.915µs] or [+19.855%; +20.547%]

scenario:iastaspects-rstrip_aspect

  • 🟥 execution_time [+103.415µs; +108.894µs] or [+30.585%; +32.206%]

scenario:iastaspectsospath-ospathbasename_aspect

  • 🟥 execution_time [+146.060µs; +152.550µs] or [+39.642%; +41.404%]

scenario:iastaspectssplit-rsplit_aspect

  • 🟥 execution_time [+30.620µs; +34.652µs] or [+19.570%; +22.148%]

scenario:span-start

  • 🟥 execution_time [+1.636ms; +2.081ms] or [+13.319%; +16.937%]

scenario:telemetryaddmetric-1-count-metric-1-times

  • 🟥 execution_time [+222.051ns; +258.237ns] or [+11.605%; +13.496%]

scenario:tracer-small

  • 🟥 execution_time [+46.501µs; +47.877µs] or [+18.891%; +19.451%]

Known flaky benchmarks without significant changes:

  • scenario:errortrackingflasksqli-baseline
  • scenario:flasksimple-iast-get
  • scenario:iastaspects-casefold_aspect
  • scenario:iastaspects-casefold_noaspect
  • scenario:iastaspects-index_aspect
  • scenario:iastaspects-ljust_noaspect
  • scenario:iastaspects-lower_aspect
  • scenario:iastaspects-replace_aspect
  • scenario:iastaspects-swapcase_aspect
  • scenario:iastaspects-title_noaspect
  • scenario:iastaspects-translate_aspect
  • scenario:iastaspects-translate_noaspect
  • scenario:iastaspects-upper_noaspect
  • scenario:packagespackageforrootmodulemapping-cache_off
  • scenario:packagespackageforrootmodulemapping-cache_on
  • scenario:sethttpmeta-all-enabled
  • scenario:telemetryaddmetric-record-100-metrics

@litianningdatadog
litianningdatadog force-pushed the tianning.li/2-flask-web-request-starting-event branch from d59e112 to 16a5332 Compare August 24, 2026 02:23
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from 3c0ea31 to eabf5ec Compare August 24, 2026 02:24
@litianningdatadog
litianningdatadog force-pushed the tianning.li/2-flask-web-request-starting-event branch from 16a5332 to 8dd7e8e Compare August 24, 2026 02:31
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from eabf5ec to 5853b4a Compare August 24, 2026 02:31
@litianningdatadog
litianningdatadog force-pushed the tianning.li/2-flask-web-request-starting-event branch 5 times, most recently from cde3045 to a0e3c42 Compare August 24, 2026 23:56
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from 5853b4a to 7afb3c1 Compare August 25, 2026 13:23
@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 25, 2026 •

Copy link
Copy Markdown

Codeowners resolved as

Resolved from the full PR diff against tianning.li/3-wsgi-asgi-integration-based-refresh using the target branch CODEOWNERS file.
CODEOWNERS team requests not listed below are not required by the current file set.

ddtrace/__init__.py                                                     @DataDog/python-guild
ddtrace/_trace/processor/__init__.py                                    @DataDog/apm-sdk-capabilities-python
ddtrace/_trace/span.py                                                  @DataDog/apm-sdk-capabilities-python @DataDog/apm-core-python
ddtrace/_trace/tracer.py                                                @DataDog/apm-sdk-capabilities-python
ddtrace/internal/ci_visibility/writer.py                                @DataDog/ci-app-libraries
ddtrace/internal/writer/writer.py                                       @DataDog/apm-core-python
ddtrace/trace/__init__.py                                               @DataDog/apm-sdk-capabilities-python
tests/tracer/runtime/test_runtime_id.py                                 @DataDog/apm-sdk-capabilities-python
tests/tracer/test_writer.py                                             @DataDog/apm-sdk-capabilities-python

@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 25, 2026 •

Copy link
Copy Markdown

Circular import analysis

⚠️ Existing circular imports

There are 1 circular imports that already exist on the base branch and have not been changed by this PR.

ddtrace.errortracking._handled_exceptions.bytecode_injector -> ddtrace.errortracking._handled_exceptions.callbacks -> ddtrace.errortracking._handled_exceptions.collector -> ddtrace.errortracking._handled_exceptions.bytecode_reporting -> ddtrace.errortracking._handled_exceptions.bytecode_injector

@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 25, 2026 •

Copy link
Copy Markdown

Dependency direction analysis

⚠️ Existing dependency direction violations

There are 205 dependency direction violations that already exist on the base branch and have not been changed by this PR.

Show existing violations (showing 5 of 205 highest severity)
ddtrace.internal.tracemethods -×-> ddtrace.trace  (internal-core -> product:tracing, score=132)
ddtrace.profiling.collector.pytorch -×-> ddtrace.trace  (product:profiling -> product:tracing, score=130)
ddtrace.llmobs._telemetry -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=130)
ddtrace.appsec._contrib.django -×-> ddtrace.trace  (product:appsec -> product:tracing, score=130)
ddtrace.llmobs._integrations.litellm -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=130)

To see all violations, download the layers-base.json and layers-pr.json artifacts from this CI job and run:

uv run --script scripts/import-analysis/layers.py compare layers-base.json layers-pr.json

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the native trace writer so that when runtime identity is refreshed (e.g., AWS Lambda MicroVM /run refresh), the native exporter is rebuilt to pick up the new runtime id captured at exporter construction time.

Changes:

  • Wire NativeWriter to runtime-id change notifications and rebuild the exporter on identity refresh.
  • Add tests to verify the exporter is rebuilt (without recreating the writer/buffer) and that the wiring works end-to-end via runtime.refresh_identity().

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
ddtrace/internal/writer/writer.py Subscribes to runtime-id change events and rebuilds the native exporter on identity refresh.
tests/tracer/test_writer.py Adds unit + subprocess tests ensuring identity refresh rebuilds the exporter without replacing the writer’s client/buffer state.
Suppressed comments (2)

ddtrace/internal/writer/writer.py:945

  • _on_identity_refresh can raise if _create_exporter() fails (e.g., native builder/telemetry initialization error). Because runtime.refresh_identity() iterates callbacks without exception handling, a failure here will propagate out of refresh_identity() and can also prevent other runtime-id listeners from running. It’s safer to only swap the exporter after successfully creating the replacement, and to swallow/log failures from the rebuild path.
        old_exporter = self._exporter
        self._exporter = self._create_exporter()
        try:
            old_exporter.shutdown(3_000_000_000)
        except Exception:

ddtrace/internal/writer/writer.py:944

  • Exporter rebuild/swap is not synchronized with payload sending. NativeWriter.flush_queue() can run on the periodic thread and can also be called from other threads, while _on_identity_refresh swaps self._exporter and shuts down the old exporter. Without a lock, this introduces a race where a concurrent _exporter.send() can observe a half-transition or have its exporter shutdown mid-send.

Consider adding a dedicated lock (similar to HTTPWriter._conn_lck) and holding it in _send_payload(), _on_identity_refresh(), set_test_session_token(), and any other place that swaps/shuts down the exporter.

        old_exporter = self._exporter
        self._exporter = self._create_exporter()
        try:
            old_exporter.shutdown(3_000_000_000)

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread ddtrace/internal/writer/writer.py Outdated
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from 6332ba7 to 6231eed Compare September 3, 2026 20:49
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-wsgi-asgi-integration-based-refresh branch from 2c58627 to 99e2b4e Compare September 4, 2026 15:10
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from 6231eed to 6006fd6 Compare September 4, 2026 15:16
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-wsgi-asgi-integration-based-refresh branch 2 times, most recently from 676adf4 to 18c03c4 Compare September 4, 2026 15:43
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from 6006fd6 to e1c70b6 Compare September 4, 2026 15:45
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-wsgi-asgi-integration-based-refresh branch from 18c03c4 to a637bb2 Compare September 4, 2026 16:49
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from e1c70b6 to 0d8f72e Compare September 4, 2026 17:32
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-wsgi-asgi-integration-based-refresh branch from a637bb2 to 0d53833 Compare September 4, 2026 17:36
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-wsgi-asgi-integration-based-refresh branch 2 times, most recently from 6e5799f to 75def6a Compare September 4, 2026 20:44
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch 2 times, most recently from f94e6ae to 92a469d Compare September 7, 2026 20:23
@litianningdatadog litianningdatadog removed the changelog/no-changelog A changelog entry is not required for this PR. label Sep 7, 2026
@litianningdatadog litianningdatadog changed the title chore(tracer): rebuild native writer exporter on identity refresh fix(tracer): refresh writer and drop stale buffers on identity refresh Sep 7, 2026
@litianningdatadog
litianningdatadog requested review from a team and removed request for a team September 7, 2026 20:24
@litianningdatadog litianningdatadog added the changelog/no-changelog A changelog entry is not required for this PR. label Sep 7, 2026
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from 92a469d to 5a48d93 Compare September 7, 2026 20:31
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-25T17:36:34.954749Z 1a8c91d Draft marked ready
🔒 Security Review ✅ Completed 2026-09-25T17:34:07.601957Z 1a8c91d Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7f7d597465

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ddtrace/internal/writer/writer.py Outdated
Comment thread ddtrace/_trace/processor/__init__.py Outdated
Comment thread ddtrace/_trace/tracer.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1a8c91d0c5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ddtrace/_trace/tracer.py
Comment thread ddtrace/_trace/tracer.py
Comment thread ddtrace/_trace/processor/__init__.py
Comment thread ddtrace/_trace/processor/__init__.py Outdated
Comment thread ddtrace/internal/writer/writer.py
Comment thread ddtrace/_trace/processor/__init__.py Outdated

@datadog-datadog-prod-us1-2 datadog-datadog-prod-us1-2 Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bits Code Review: FAIL

Two of the most critical issues are: (1) on_span_finish in processor/__init__.py mutates trace aggregation state before checking the finishing span's generation, enabling stale spans to corrupt or prematurely export current-generation traces; and (2) start_span in tracer.py assigns the current generation to spans whose parent is a local Context (not a Span), allowing pre-refresh stale traces to pass generation checks and reach the replacement writer.

Open Bits AI session

🤖 Bits Code Review · Commit 0ea9a2f · @DataDog review to ask questions

# Capture the generation before processing so an identity refresh can invalidate this trace.
identity_generation = self._runtime_identity_generation
if identity_generation is not None and any(
finished_span._get_ctx_item(_RUNTIME_IDENTITY_GENERATION_KEY) != identity_generation

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Reject stale completions before updating trace counts

If an old span finishes after refresh and a new span shares its trace ID, on_span_finish increments the new trace's completion count before checking identity. With one unfinished new span buffered, this removes the trace and submits that unfinished span. The added check accepts it because it examines buffered spans rather than the stale finishing span. Check the finishing span's generation under the lock before modifying aggregation state.

Was this helpful? React 👍 or 👎
🤖 Bits Code Review · @DataDog review to ask questions · Open Bits AI session

Comment thread ddtrace/_trace/tracer.py
identity_generation = None
if self._span_aggregator._identity_refresh_enabled:
identity_generation = self._span_aggregator._capture_identity_generation()
if parent is not None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Preserve identity generations through local Context propagation

Instrumented ThreadPoolExecutor work submitted before refresh carries a copied Context, not a Span. If it starts after refresh, parent is None here, so its spans receive the current generation while retaining the old trace and parent IDs. They pass the generation checks and reach the replacement writer despite belonging to the discarded trace. Preserve identity generations through local Context propagation while continuing to accept remote request contexts.

Was this helpful? React 👍 or 👎
🤖 Bits Code Review · @DataDog review to ask questions · Open Bits AI session

for client in self._clients:
getattr(client.encoder, "flush")()
if not self._exporter_dropped:
self._drop_exporter()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Stop native workers before discarding the exporter

During MicroVM refresh, TraceExporterPy.drop() discards its inner exporter without stopping workers registered with the shared runtime. NativeWriter's existing destructor documents that explicit shutdown is required, but setting _exporter_dropped bypasses the remaining cleanup paths. Old workers therefore remain registered alongside their replacements. Refresh needs a non-flushing worker cancellation path before discarding the exporter.

Was this helpful? React 👍 or 👎
🤖 Bits Code Review · @DataDog review to ask questions · Open Bits AI session

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

aws-microvm Work related to AWS MicroVM onboarding changelog/no-changelog A changelog entry is not required for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants