Skip to content

chore(flask): emit MicroVM request-starting event - #19816

Closed
litianningdatadog wants to merge 1 commit into
tianning.li/1-runtime-identity-refreshfrom
tianning.li/2-flask-web-request-starting-event
Closed

litianningdatadog wants to merge 1 commit into
tianning.li/1-runtime-identity-refreshfrom
tianning.li/2-flask-web-request-starting-event

Conversation

@litianningdatadog

@litianningdatadog litianningdatadog commented Aug 23, 2026 •

Copy link
Copy Markdown
Contributor

Stacked PRs:

Description

Add a Flask request-starting event that fires before the request/root span is created, but only when running in an AWS Lambda MicroVM environment.

The immediate use case is AWS Lambda MicroVMs: the POST /aws/lambda-microvms/runtime/v1/run hook needs to refresh runtime identity before the root span reads it. Flask receives mounted/prefixed WSGI requests as SCRIPT_NAME plus PATH_INFO, so the dispatched path uses the canonical WSGI request path: (SCRIPT_NAME or "").rstrip("/") + (PATH_INFO or "").

This PR also adds ddtrace.internal.serverless.in_aws_lambda_microvm() so future web integrations can share the same MicroVM environment check instead of each integration reading AWS_LAMBDA_MICROVM_IMAGE_ARN directly.

I also moved the web event-name strings into ddtrace.internal.core.event_names. That gives lower-level code a shared place to import WEB_REQUEST_STARTING without depending on ddtrace.contrib. Importing contrib during import ddtrace is unsafe because it can pull in trace handlers before ddtrace.config is exported.

Replaces #19779 after the branch rename broke the original PR association.

Testing

  • scripts/lint fmt ddtrace/internal/serverless/__init__.py ddtrace/contrib/internal/flask/patch.py tests/contrib/flask/test_microvm_identity_refresh.py tests/internal/test_serverless.py
  • uv run --script scripts/import-analysis/cycles.py analyze /tmp/ddtrace-cycles-after.json
    • No cycle involving ddtrace.internal.serverless, ddtrace.contrib.internal.flask.patch, or ddtrace.internal.settings; existing repo total remains 3.
  • scripts/run-tests --venv 12c5734 -- -- tests/internal/test_serverless.py
    • Blocked locally during collection/build by the existing native-extension mismatch: ImportError: cannot import name 'process_metrics' from 'ddtrace.internal.native._native'
  • scripts/run-tests --venv f3bee4b -- -- tests/contrib/flask/test_microvm_identity_refresh.py
    • Blocked locally during collection/build by the same native-extension mismatch.

Risks

Low. The Flask dispatch is internal and gated to AWS Lambda MicroVM environments.

Release note

None. Internal-only event plumbing; use changelog/no-changelog.

Stack

Depends on #19778. Follow-ups add more emitters and the runtime-id refresh listener.

@litianningdatadog litianningdatadog added the changelog/no-changelog A changelog entry is not required for this PR. label Aug 23, 2026
@litianningdatadog
litianningdatadog requested a review from a team as a code owner August 23, 2026 20:53
@litianningdatadog litianningdatadog added the aws-microvm Work related to AWS MicroVM onboarding label Aug 23, 2026
@litianningdatadog
litianningdatadog requested a review from a team as a code owner August 23, 2026 20:53
@litianningdatadog
litianningdatadog requested review from brettlangdon, dubloom and emmettbutler and a lite review from Copilot and removed request for juanjux August 23, 2026 20:54

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 introduces a new internal web-framework event (WebFrameworkEvents.WEB_REQUEST_STARTING) and emits it from the Flask integration at WSGI entry, intended to let downstream logic observe method/path before Flask request context and the root web span are created (motivated by the MicroVM /run identity-refresh ordering constraint).

Changes:

  • Add WebFrameworkEvents.WEB_REQUEST_STARTING = "web.request.starting".
  • Emit the event from ddtrace.contrib.internal.flask.patch.patched_wsgi_app() as soon as REQUEST_METHOD and path info are available in the WSGI environ.
  • Add Flask tests asserting the event is emitted (including for 404s) and that emission happens before the Flask WSGI middleware runs.

Reviewed changes

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

File Description
ddtrace/contrib/_events/web_framework.py Adds the new WEB_REQUEST_STARTING enum value.
ddtrace/contrib/internal/flask/patch.py Dispatches the new pre-request event at Flask WSGI entry.
tests/contrib/flask/test_microvm_identity_refresh.py Adds coverage validating the event is emitted and ordered before tracing/middleware.

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

Comment on lines +42 to +54
events = []
environ = {"REQUEST_METHOD": "POST", "PATH_INFO": REQUEST_STARTING_PATH, "SCRIPT_NAME": ""}

def start_response(status, headers, exc_info=None):
pass

def wrapped(environ, start_response):
return []

def dispatch(name, args):
if name == WebFrameworkEvents.WEB_REQUEST_STARTING.value:
events.append("starting")

Comment thread ddtrace/contrib/internal/flask/patch.py Outdated
@datadog-datadog-us1-prod

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

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

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

@cit-pr-commenter-54b7da

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

Copy link
Copy Markdown

Dependency direction analysis

⚠️ Existing dependency direction violations

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

Show existing violations (showing 5 of 250 highest severity)
ddtrace.internal.tracemethods -×-> ddtrace.trace  (internal-core -> product:tracing, score=135)
ddtrace.appsec._contrib.flask -×-> ddtrace.trace  (product:appsec -> product:tracing, score=133)
ddtrace.llmobs._telemetry -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=133)
ddtrace.profiling.collector.pytorch -×-> ddtrace.trace  (product:profiling -> product:tracing, score=133)
ddtrace.llmobs._integrations.google_adk -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=133)

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

@pr-commenter

pr-commenter Bot commented Aug 24, 2026 •

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-08-25 00:18:27

Comparing candidate commit a0e3c42 in PR branch tianning.li/2-flask-web-request-starting-event with baseline commit 3bb9ecd in branch main.

📊 Benchmarking dashboard

Found 0 performance improvements and 0 performance regressions! Performance is the same for 70 metrics, 0 unstable metrics.

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 ----------------------------------'

@litianningdatadog
litianningdatadog force-pushed the tianning.li/2-flask-web-request-starting-event branch from d4c1810 to 12b6c50 Compare August 24, 2026 15:31
@litianningdatadog
litianningdatadog requested review from a team as code owners August 24, 2026 15:31
@litianningdatadog
litianningdatadog requested review from DarcyRaynerDD, apiarian-datadog and florentinl and removed request for a team August 24, 2026 15:31
@litianningdatadog litianningdatadog changed the title chore(flask): emit pre-request web event feat(flask): emit MicroVM request-starting event Aug 24, 2026
@litianningdatadog
litianningdatadog force-pushed the tianning.li/2-flask-web-request-starting-event branch 2 times, most recently from 0fa6836 to cde3045 Compare August 24, 2026 17:19
@litianningdatadog litianningdatadog changed the title feat(flask): emit MicroVM request-starting event chore(flask): emit MicroVM request-starting event Aug 24, 2026
@litianningdatadog litianningdatadog added changelog/no-changelog A changelog entry is not required for this PR. and removed changelog/no-changelog A changelog entry is not required for this PR. labels Aug 24, 2026
Comment thread ddtrace/internal/serverless/__init__.py Outdated
Define web request event names in ddtrace.internal.core.event_names so integrations and lower-level runtime hooks can depend on the same event strings without duplicating literals.

The MicroVM runtime hook needs WEB_REQUEST_STARTING during ddtrace bootstrap. Importing ddtrace.contrib from that path can load trace handlers that import top-level ddtrace.config before __init__ has exported it, producing a circular import in MicroVM images. Keeping the names in a core constants-only module gives both contrib and runtime a safe dependency point.
script_name = (environ.get("SCRIPT_NAME") or "").rstrip("/")
if in_aws_lambda_microvm():
path_info = environ.get("PATH_INFO") or ""
core.dispatch(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If we do this from the base wsgi middleware, will it happen early enough for you, and also hit a larger number of web integrations in 1 go?

same with the asgi base setup?

it shouldn't stop us from adding test cases per-integration that this is being handled properly, but would save us from needing to mimic the same event firing from all integrations.

wdyt?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

or, does the existing wsgi.__call__ event happen early enough, we can just hook into that one without needing to add a new event (if there are no listeners, dispatching events is cheap, but still incurs a cost)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestion! Not aware that dd-trace-py already has wsgi/asgi handling. I think patching them would cover many cases. For other cases such as python stdlib http.server, it would require integration work #19817.

environ, start_response = args
script_name = (environ.get("SCRIPT_NAME") or "").rstrip("/")
if in_aws_lambda_microvm():
path_info = environ.get("PATH_INFO") or ""

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.

I'm not sure I understand entirely what's happening here, so apologies if the question is silly, but shouldn't we be checking for the expected /run request at some point? It looks like we always emit the starting event as soon as we get a request within a MicroVM instance

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes we can add pre-check here to minimize the event firing. To answer your question, the path check occurs on the listener side in the followup PR
https://github.com/DataDog/dd-trace-py/pull/19825/changes#diff-433e6ca1c168b17797cede9c3332a99224d530e0edbfdd2cceafeafd8bf79c51R105

@emmettbutler
emmettbutler marked this pull request as draft August 26, 2026 17:37

@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.

Marked as draft because the base is not main.

@litianningdatadog

Copy link
Copy Markdown
Contributor Author

close it as it is covered by wsgi/asgi patch

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.

6 participants