Skip to content

fix(telemetry): rebuild worker on identity refresh - #19821

Open
litianningdatadog wants to merge 1 commit into
tianning.li/3-3-trace-writer-identity-refreshfrom
tianning.li/3-4-telemetry-identity-refresh
Open

litianningdatadog wants to merge 1 commit into
tianning.li/3-3-trace-writer-identity-refreshfrom
tianning.li/3-4-telemetry-identity-refresh

Conversation

@litianningdatadog

@litianningdatadog litianningdatadog commented Aug 23, 2026 •

Copy link
Copy Markdown
Contributor

Stacked PRs:

Description

Telemetry has the same stale-identity problem as traces. The native telemetry worker is created with the runtime identity available at that time, so an explicit MicroVM identity refresh must replace the worker before later telemetry is sent.

TelemetryWriter registers with the explicit identity-refresh callback registry only when running in a MicroVM (in_aws_lambda_microvm()); elsewhere the callback is never installed and the writer behaves as before. On refresh, it discards the current worker (without flushing its queued telemetry when the native drop() API is available; see below), clears the worker binding, and builds a fresh worker. If the previous worker had reported app-started, startup is reported again under the refreshed identity.

A worker rebuild starts with empty native state. The writer therefore replays accepted configuration events in sequence order and restores the latest integration and product-activation state on the replacement worker. Dependency reporting uses preserved tracker state and forces a full re-report so previously collected dependency metadata and SCA metadata are not lost.

Refresh can race with reporting calls that read or write self._worker (metrics, integrations, endpoints, configuration, logs, lifecycle, and fork handling). Each worker-accessing method now has a lock-free _without_lock implementation behind a public conditional-lock wrapper. MicroVM writers use the existing re-entrant lock; non-MicroVM writers use None and call the helper directly, avoiding nullcontext() overhead on normal hot paths.

Production status / native dependency

The preferred refresh path discards the old worker with the native TelemetryWorker.drop() API, which does not flush its queue. This branch pins libdatadog v43.0.1, whose TelemetryWorker exposes stop() but not drop().

Until the native API is available, refresh falls back to stop() and logs a warning. The worker is still rebuilt with the refreshed runtime and session IDs, but stop() flushes the old runtime's queued telemetry (under the old IDs) and emits app-closing; its send_app_closing argument is currently ineffective. Raising instead would fail the MicroVM /run lifecycle request, so this degraded behavior is preferred. Once TelemetryWorker.drop() ships, the existing getattr(worker, "drop", None) check uses it automatically.

Reference

Testing

Added focused coverage for:

  • rebuilding the worker with refreshed runtime and session IDs
  • discarding the old worker without calling stop() or flushing its queue when drop() is available
  • falling back to stop() with a warning when the native worker has no drop()
  • propagating discard failures without mutating the old worker state
  • retrying after replacement-worker build failure and preserving app-started lifecycle state
  • restoring app-started state when needed
  • replaying configuration, integration, and product-activation state
  • registering the identity-refresh callback only for MicroVM writers
  • serializing metric recording against a concurrent identity refresh
  • re-reporting preserved dependency metadata after refresh(), with and without SCA enabled
  • no-op writer compatibility and explicit callback registration

Validation:

  • scripts/lint fmt: passed
  • scripts/lint style: passed
  • tests/telemetry/test_writer.py: 71 passed, 1 skipped (Python 3.12)

Risks

Low outside MicroVM environments: the identity-refresh callback is never registered there, and non-MicroVM worker access remains lock-free. Inside MicroVMs, worker replacement occurs only on explicit runtime identity refresh, and the re-entrant lock serializes refresh with worker access. With the current native pin, refresh succeeds through the stop() fallback; the cost is that stale telemetry is flushed under the old identity (bounded by the flush interval) and may be duplicated across clones restored from one snapshot. Native/libdatadog changes are not included in this PR.

Files (12)

  • ddtrace/internal/_runtime_id.py [MODIFIED] (+5 -0)
  • ddtrace/internal/runtime/init.py [MODIFIED] (+2 -0)
  • ddtrace/internal/telemetry/dependency.py [MODIFIED] (+4 -0)
  • ddtrace/internal/telemetry/dependency_tracker.py [MODIFIED] (+12 -6)
  • ddtrace/internal/telemetry/noop_writer.py [MODIFIED] (+7 -1)
  • ddtrace/internal/telemetry/writer.py [MODIFIED] (+382 -83)
  • ddtrace/internal/writer/writer.py [MODIFIED] (+35 -3)
  • releasenotes/notes/fix-telemetry-worker-identity-refresh-19fe1775be48b696.yaml [ADDED] (+5 -0)
  • tests/appsec/sca/test_telemetry.py [MODIFIED] (+1 -0)
  • tests/telemetry/test_dependency.py [MODIFIED] (+49 -1)
  • tests/telemetry/test_writer.py [MODIFIED] (+455 -0)
  • tests/tracer/test_writer.py [MODIFIED] (+41 -0)

🤖 Generated with Claude Code

@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
@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 23, 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 23, 2026 •

Copy link
Copy Markdown

Dependency direction analysis

⚠️ Existing dependency direction violations

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

Show existing violations (showing 5 of 201 highest severity)
ddtrace.internal.tracemethods -×-> ddtrace.trace  (internal-core -> product:tracing, score=132)
ddtrace.llmobs._evaluators.runner -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=130)
ddtrace.llmobs._integrations.openai_agents -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=130)
ddtrace.llmobs._integrations.llama_index -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=130)
ddtrace.debugging._signal.model -×-> ddtrace.trace  (product:debugging -> 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

@cit-pr-commenter-54b7da

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

Copy link
Copy Markdown

Codeowners resolved as

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

ddtrace/internal/_runtime_id.py                                         @DataDog/apm-core-python
ddtrace/internal/runtime/__init__.py                                    @DataDog/apm-sdk-capabilities-python
ddtrace/internal/telemetry/dependency.py                                @DataDog/apm-python
ddtrace/internal/telemetry/dependency_tracker.py                        @DataDog/apm-python
ddtrace/internal/telemetry/noop_writer.py                               @DataDog/apm-python
ddtrace/internal/telemetry/writer.py                                    @DataDog/apm-python
ddtrace/internal/writer/writer.py                                       @DataDog/apm-core-python
releasenotes/notes/fix-telemetry-worker-identity-refresh-19fe1775be48b696.yaml  @DataDog/apm-python
tests/appsec/sca/test_telemetry.py                                      @DataDog/asm-python
tests/telemetry/test_dependency.py                                      @DataDog/apm-core-python @DataDog/apm-python
tests/telemetry/test_writer.py                                          @DataDog/apm-core-python @DataDog/apm-python
tests/tracer/test_writer.py                                             @DataDog/apm-sdk-capabilities-python

@litianningdatadog litianningdatadog changed the title fix(telemetry): rebuild worker on identity refresh chore(telemetry): rebuild worker 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

Tests

✅ All CI checks and tests passed.

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 8529b92 | 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-10-01 18:49:52

Comparing candidate commit 8529b92 in PR branch tianning.li/3-4-telemetry-identity-refresh with baseline commit a23e56e in branch tianning.li/3-3-trace-writer-identity-refresh.

📊 Benchmarking dashboard

Found 0 performance improvements and 5 performance regressions! Performance is the same for 355 metrics, 9 unstable metrics, 4 known flaky benchmarks, 4 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-b3_single_headers

  • 🟥 execution_time [+1.263µs; +1.334µs] or [+18.503%; +19.548%]

scenario:httppropagationextract-empty_headers

  • 🟥 execution_time [+92.338ns; +107.885ns] or [+12.531%; +14.640%]

scenario:httppropagationextract-wsgi_valid_headers_basic

  • 🟥 execution_time [+346.679ns; +397.480ns] or [+9.074%; +10.404%]

scenario:msgpackencoderscenario-simple_one_span

  • 🟥 execution_time [+515.522ns; +577.646ns] or [+12.658%; +14.184%]

scenario:otelspan-start

  • 🟥 execution_time [+1.831ms; +2.673ms] or [+7.097%; +10.364%]

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 [-801.608ns; +658.245ns] or [-7.648%; +6.280%]

scenario:coreapiscenario-core_dispatch_1_listener

  • unstable execution_time [-30.551ns; +47.509ns] or [-4.644%; +7.222%]

scenario:coreapiscenario-core_dispatch_50_listeners

  • unstable execution_time [-1916.296ns; +1907.038ns] or [-9.673%; +9.626%]

scenario:coreapiscenario-core_dispatch_exception_listeners

  • unstable execution_time [-1544.903ns; +2060.842ns] or [-8.251%; +11.006%]

scenario:coreapiscenario-core_dispatch_listeners

  • unstable execution_time [-393.926ns; +364.704ns] or [-9.262%; +8.575%]

scenario:coreapiscenario-core_dispatch_no_args_listeners

  • unstable execution_time [-236.498ns; +221.868ns] or [-8.861%; +8.313%]

scenario:coreapiscenario-core_dispatch_with_results_1_listener

  • unstable execution_time [-84.826ns; +98.106ns] or [-6.306%; +7.293%]

scenario:coreapiscenario-core_dispatch_with_results_50_listeners

  • unstable execution_time [-4324.911ns; +4999.464ns] or [-9.002%; +10.406%]

scenario:coreapiscenario-core_dispatch_with_results_listeners

  • unstable execution_time [-944.466ns; +937.175ns] or [-9.263%; +9.192%]

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.991µs; +3.103µs] or [+21.204%; +21.995%]

scenario:span-start

  • 🟥 execution_time [+1.276ms; +1.722ms] or [+9.465%; +12.776%]

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

  • 🟥 execution_time [+341.379ns; +375.180ns] or [+17.963%; +19.742%]

scenario:tracer-small

  • 🟥 execution_time [+37.829µs; +39.226µs] or [+14.035%; +14.554%]

Known flaky benchmarks without significant changes:

  • scenario:errortrackingflasksqli-baseline
  • scenario:flasksimple-iast-get
  • 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-4-telemetry-identity-refresh branch from 2165d36 to a44a4b8 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-4-telemetry-identity-refresh branch from a44a4b8 to 2b1bf99 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-4-telemetry-identity-refresh branch from 2b1bf99 to b4e8c78 Compare August 25, 2026 13:23
@litianningdatadog
litianningdatadog requested a lite review from Copilot August 25, 2026 13:36

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

Ensure telemetry emitted after a runtime identity refresh uses the refreshed runtime ID by tearing down the existing native telemetry worker and allowing it to be rebuilt.

Changes:

  • Wire TelemetryWriter to runtime identity changes and rebuild (drop) its native worker on refresh.
  • Stop the live native worker during identity refresh to prevent continued heartbeats with stale identity.
  • Add tests covering worker teardown on identity refresh and wiring through runtime.refresh_identity().

Reviewed changes

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

File Description
ddtrace/internal/telemetry/writer.py Subscribes to runtime-id changes and stops/drops the native telemetry worker on identity refresh.
tests/telemetry/test_writer.py Adds identity-refresh tests for worker stop/drop behavior and wiring through runtime.refresh_identity().

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

Comment thread tests/telemetry/test_writer.py Outdated
Comment thread ddtrace/internal/telemetry/writer.py Outdated
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from 982f582 to 9c54e0e Compare September 21, 2026 21:21
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-4-telemetry-identity-refresh branch 5 times, most recently from 24f368e to fb190e7 Compare September 22, 2026 05:38
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from 7d904ad to f2664ed Compare September 22, 2026 20:21
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-4-telemetry-identity-refresh branch from fb190e7 to e96b84d Compare September 22, 2026 20:25
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch 2 times, most recently from 8376c12 to ba3f177 Compare September 23, 2026 19:18
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-4-telemetry-identity-refresh branch from e96b84d to b51f682 Compare September 23, 2026 19:27
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from ba3f177 to 805d8d1 Compare September 23, 2026 19:41
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-4-telemetry-identity-refresh branch 3 times, most recently from f7876cb to b84f21b Compare September 24, 2026 15:37
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from 805d8d1 to 8dbfa50 Compare September 24, 2026 17:40
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-4-telemetry-identity-refresh branch 2 times, most recently from 156be45 to c8b45b6 Compare September 24, 2026 17:57
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from 8dbfa50 to 19be48b Compare September 24, 2026 18:25
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-4-telemetry-identity-refresh branch from c8b45b6 to c641a12 Compare September 24, 2026 18:29
@litianningdatadog
litianningdatadog force-pushed the tianning.li/3-3-trace-writer-identity-refresh branch from 19be48b to 7f7d597 Compare September 24, 2026 19:13
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 29, 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-10-01T18:23:05.229099Z 8529b92 New commits
🔒 Security Review ✅ Completed 2026-10-01T18:23:50.507231Z 8529b92 New commits
ℹ️ 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: 359a1ce7d0

ℹ️ 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 on lines +466 to +472
if discard is None:
log.warning(
"Native TelemetryWorker does not support discard; stopping the worker %s. "
"Upgrade the native ddtrace dependency to avoid flushing stale telemetry.",
reason,
)
self._stop_worker(False, reason)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Fail refresh when the worker lacks discard support

With the currently pinned libdatadog v43.0.1, TelemetryWorker has no drop() method—the wrapper in src/native/telemetry.rs:254-280 only exposes stop(), which explicitly ignores send_app_closing, drains queued data, and emits app-closing. Consequently every MicroVM identity refresh takes this fallback, flushes telemetry carrying the previous runtime identity, and then returns successfully so the identity coordinator will not retry. This preserves the exact cross-invocation misattribution being fixed; the callback should fail without stopping until a non-flushing discard operation is available.

Useful? React with 👍 / 👎.

Comment on lines +474 to +477
discard()
self._worker = None
self.started = False
_unbind_metric_recorders(self)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Synchronize MetricRecorder calls before discarding the worker

During a MicroVM refresh concurrent callers using get_metric_recorder() remain unsynchronized: MetricRecorder.add() in ddtrace/internal/telemetry/metrics.py:231-235 reads its worker and calls add_point() without _worker_access_lock, while this path discards the native worker before rebinding recorders. Such a caller can therefore submit to the old worker after the runtime ID has rotated or race its teardown, losing or misattributing the metric despite the new locking around TelemetryWriter.add_*_metric().

Useful? React with 👍 / 👎.

Comment on lines +1208 to +1210
if was_started:
self.app_started()
self._identity_refresh_started = False

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Propagate replacement worker start failures

If the old worker had started but the replacement worker's native start() call fails, app_started() catches the exception and returns with self.started still false. This code nevertheless clears _identity_refresh_started and returns success, causing the /run identity coordinator to remove the callback from its retry queue and mark the refresh complete; telemetry then remains permanently unstarted for that logical runtime. Verify self.started after this call and raise so the existing refresh retry mechanism can run again.

Useful? React with 👍 / 👎.

Comment on lines +368 to +370
if get_parent_runtime_id() is None:
if not self.started:
self.add_configurations(get_python_config_vars())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid re-recording bootstrap configurations after replay

On every root-process identity rebuild, _replay_worker_state() has already copied all accepted configurations—including the initial get_python_config_vars() entries—into the replacement worker, but _discard_worker() reset started to false, so this branch immediately records the Python configuration list a second time with new sequence IDs. The replacement therefore reports duplicate configuration changes on every refresh, and the duplicates are appended back into the bounded 5,000-entry replay deque, potentially evicting real earlier configuration events near the limit. Bootstrap configurations should only be added for the initial worker, not after a state replay.

Useful? React with 👍 / 👎.

Comment on lines +982 to +986
if self._worker_access_lock:
with self._worker_access_lock:
self._add_count_metric_without_lock(namespace, name, value, tags)
else:
self._add_count_metric_without_lock(namespace, name, value, tags)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve the metric fast path outside MicroVMs

For every normal non-MicroVM process, _worker_access_lock is None, yet each of the four metric APIs now performs an extra Python helper call per point. The previous implementation explicitly kept these bodies inline because avoiding that call frame measurably lowers overhead, and these methods run for every IAST aspect and propagation injection; this therefore regresses the dominant production path even though it requires no refresh synchronization. Keep the existing body inline for the None branch or select a specialized implementation once at initialization.

AGENTS.md reference: AGENTS.md:L16-L16

Useful? React with 👍 / 👎.

@emmettbutler emmettbutler left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Deferring review since the base branch is not main

"Upgrade the native ddtrace dependency to avoid flushing stale telemetry.",
reason,
)
self._stop_worker(False, reason)

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.

P1 Reject refresh when discard support is unavailable

When the pinned native worker lacks drop(), identity refresh calls stop(), flushing queued telemetry and app-closing under the stale runtime identity. The callback then succeeds instead of remaining retryable, defeating the refresh contract for MicroVM users; raise without mutating the worker and update the legacy-worker test accordingly.

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

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 Remove the production test warning

Every expected MicroVM identity refresh emits a warning claiming a test regenerated the runtime ID. This creates misleading application-log noise and exposes both runtime IDs during normal production lifecycle handling.

Suggested change
_refresh_runtime_id()

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

@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

With the pinned worker lacking drop(), MicroVM refresh flushes old-identity telemetry and reports success instead of remaining retryable. Expected refreshes also emit a misleading test warning.

Open Bits AI session

🤖 Bits Code Review · Commit 359a1ce · @DataDog review to ask questions

@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: ee6f68585c

ℹ️ 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".

# all child hooks have completed, without unparking the inherited Tokio runtime.
forksafe.register(self._fork_writer)
if self._is_microvm:
on_runtime_identity_refresh(self._refresh_runtime_identity)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Order telemetry refresh before rebuilding the trace writer

When both the tracer and this writer register refresh callbacks, _ON_RUNTIME_IDENTITY_REFRESH is a set, so callback order is nondeterministic. If the tracer callback runs first, it publishes a replacement NativeWriter whose exporter is initially attached to the old telemetry worker; a concurrent trace flush can then record trace_api.* metrics against the previous runtime until this callback runs, at which point those points are either discarded or, with the current stop fallback, flushed under the stale identity. Make the worker replacement and trace-writer rebuild deterministically ordered or otherwise atomic with respect to trace sends.

Useful? React with 👍 / 👎.

Comment on lines +1011 to +1013
telemetry_writer._subscribe_worker_changes(
self._on_telemetry_worker_changed, shared_worker, late_callback
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep the unpublished exporter synchronized after subscribing

During exporter recreation in set_test_session_token() or _downgrade(), _create_exporter() runs before the caller assigns its result to self._exporter. If an identity refresh occurs after this subscription returns but before that assignment, the stored callback updates the old self._exporter, not the newly built local exporter; the caller then publishes the new exporter still attached to the discarded worker, and no later notification corrects it. The subscription or publication must keep the local exporter targeted throughout this race window.

Useful? React with 👍 / 👎.


def remove_runtime_identity_refresh(cb: t.Callable[[str], None]) -> None:
"""Unregister a callback for explicit runtime identity refreshes."""
_ON_RUNTIME_IDENTITY_REFRESH.discard(cb)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Serialize callback removal with identity refresh

In a MicroVM, refresh_identity() iterates _ON_RUNTIME_IDENTITY_REFRESH while holding _RUNTIME_IDENTITY_REFRESH_LOCK, but telemetry shutdown can call this unsynchronized discard() concurrently. If removal occurs while line 175 converts the set into the pending callback list, Python can raise RuntimeError: Set changed size during iteration after the runtime ID has already rotated; the retry path then sees the new ID with an empty pending list and can mark the transition complete without rebuilding any registered component. Acquire the identity-refresh lock when mutating this registry.

Useful? React with 👍 / 👎.

@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: bfdcca813b

ℹ️ 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 on lines +1029 to +1030
telemetry_writer._is_microvm = True
telemetry_writer._worker_access_lock = telemetry_writer._enable_lock

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use a reentrant lock in the MicroVM test

When the native worker gains drop() and this test is no longer skipped, it will hang in runtime.refresh_identity(): the fixture constructs the writer outside a MicroVM, so _enable_lock is a non-reentrant forksafe.Lock, and assigning that same lock to _worker_access_lock means the refresh callback acquires it and then enable() tries to acquire it again after discarding the worker. Construct the writer with MicroVM detection enabled or replace both lock attributes with the same RLock before invoking the refresh.

Useful? React with 👍 / 👎.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants