Skip to content

perf(ffe): fix FEATURE_FLAGGING_AND_EXPERIMENTATION CI regression on Node.js - #7488

Draft
rochdev wants to merge 3 commits into
mainfrom
rochdev/ffe-flush-exposures
Draft

perf(ffe): fix FEATURE_FLAGGING_AND_EXPERIMENTATION CI regression on Node.js#7488
rochdev wants to merge 3 commits into
mainfrom
rochdev/ffe-flush-exposures

Conversation

@rochdev

@rochdev rochdev commented Aug 10, 2026

Copy link
Copy Markdown
Member

Summary

  • FEATURE_FLAGGING_AND_EXPERIMENTATION regressed from <3 minutes to 7+ minutes in dd-trace-js CI (nodejs express4 shard).
  • Two independent costs were identified from the real CI job log/timing breakdown, and both are fixed here:

1. Exposures: waiting on a periodic flush timer instead of flushing immediately

  • tests/ffe/test_exposures.py's wait_for_exposure_event/wait_for_min_exposure_count helpers were purely polling interfaces.agent.wait_for(..., timeout=30) for exposure events, at the mercy of the exposures writer's periodic flush interval.
  • This adds a weblog.get("/flush") call before polling, so the weblog forces its exposures writer to flush immediately via the existing /flush endpoint pattern, instead of waiting on the timer.
  • Wired the Node.js side: the 4 Node weblogs (express, express4-typescript, fastify, nextjs) now publish the ffe:writers:flush diagnostics channel (already consumed inside dd-trace-js) from their /flush handlers.
  • weblog.get("/flush") is a no-op for weblogs/languages that don't implement the route, so this is safe across all libraries.
  • Confirmed in CI: test_exposures.py now completes in ~30s instead of stalling on the writer's timer.

2. EVP flagevaluation: missing_feature tests were still executing under xfail, burning their full timeout

  • missing_feature (and bug, etc.) map to pytest.mark.xfail, not skip (utils/_decorators.py) — the test body still runs. dd-trace-js has no implementation of /api/v2/flagevaluation at all, so tests/ffe/test_flag_eval_evp.py's 8 non-@scenario_crash classes each ran to completion and burned their full 30s wait_for timeout before failing as expected. That's ~240s, the actual dominant cost of the scenario.
  • Adds @slow (existing skip_if_xfail mechanism, already used on 3 sibling classes in this file via @scenario_crash) to the remaining 8 classes. @slow only converts a test to a hard skip when it's paired with the manifest's declaration marker for the current library — so this only skips for libraries where the feature is currently declared missing (today: Node.js for all 8, plus golang for the 3 ObserveFullData_* classes it doesn't yet implement).
  • Self-healing: once a library implements the feature and its manifest entry is removed, @slow becomes a no-op and the test runs for real. Confirmed against golang's actual CI timing (the one library that implements this today) that real event delivery is on the order of 1-2s, nowhere near the 30s ceiling, so no added flakiness risk anywhere.

Test plan

  • Re-run the FEATURE_FLAGGING_AND_EXPERIMENTATION scenario for nodejs (express4/express4-typescript/fastify/nextjs) in CI and confirm it completes well under 3 minutes.
  • Confirm tests/ffe/test_exposures.py still passes for nodejs.
  • Confirm tests/ffe/test_flag_eval_evp.py still passes for golang (only the 3 ObserveFullData_* classes should skip there).
  • Confirm other languages are unaffected.

🤖 Generated with Claude Code

…imer

FEATURE_FLAGGING_AND_EXPERIMENTATION regressed to 7+ minutes in CI.
test_exposures.py's wait_for_exposure_event/wait_for_min_exposure_count
helpers were polling for up to 30s waiting on the exposures writer's
periodic flush. Force an immediate flush via the existing /flush
endpoint (already wired to a ffe:writers:flush diagnostics channel in
dd-trace-js) before polling, so events land immediately instead of on
the writer's timer.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

CODEOWNERS have been resolved as:

tests/ffe/test_exposures.py                                             @DataDog/feature-flagging-and-experimentation-sdk @DataDog/system-tests-core
tests/ffe/test_flag_eval_evp.py                                         @DataDog/feature-flagging-and-experimentation-sdk @DataDog/system-tests-core
utils/build/docker/nodejs/express/app.js                                @DataDog/dd-trace-js @DataDog/system-tests-core
utils/build/docker/nodejs/express4-typescript/app.ts                    @DataDog/dd-trace-js @DataDog/system-tests-core
utils/build/docker/nodejs/fastify/app.js                                @DataDog/dd-trace-js @DataDog/system-tests-core
utils/build/docker/nodejs/nextjs/src/app/flush/route.js                 @DataDog/dd-trace-js @DataDog/system-tests-core

@datadog-datadog-us1-prod

datadog-datadog-us1-prod Bot commented Aug 10, 2026

Copy link
Copy Markdown

Pipelines  Tests

⚠️ Warnings

🚦 3 Pipeline jobs failed

Testing the test | System Tests (php, dev) / End-to-end #2 / laravel11x 2   View in Datadog   GitHub Actions

See error Test failures due to incomplete implementation of '/make_distant_call' endpoint, leading to 6 tests marked as xfailed.

🧪 1 Test failed

tests.stats.test_stats.Test_Peer_Tags.test_peer_tags[laravel11x] from system_tests_suite   View in Datadog
AssertionError: Client spans should have peer tags, found: []
assert 0 &gt; 0
 &#43;  where 0 = len([])

self = &lt;tests.stats.test_stats.Test_Peer_Tags object at 0x7f3e2c3e01d0&gt;

    def test_peer_tags(self):
        &#34;&#34;&#34;Test that client spans include peer tags while server spans don&#39;t&#34;&#34;&#34;
        client_stats_found = False
        server_stats_found = False
...

Testing the test | System Tests (python, dev) / End-to-end #1 / flask-poc 1   View in Datadog   GitHub Actions

See error Healthcheck failed for weblog: container is not running, Failed to start container weblog due to worker boot failure.

Testing the test | all-jobs-are-green   View in Datadog   GitHub Actions

See error Some CI checks failed during execution.

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 67e5129 | Docs | Datadog PR Page | Give us feedback!

rochdev and others added 2 commits August 10, 2026 17:48
…tricted-require

express/fastify's eslint config bans require('diagnostics_channel')
via n/no-restricted-require. The node: prefixed specifier resolves to
the same core module and isn't covered by the restriction.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…iming out

These tests were still executing under xfail (missing_feature maps to
xfail, not skip), so each one burned its full wait_for timeout (~30s)
waiting for an event that can never arrive on libraries without the
feature. @slow pairs with the manifest's declaration marker to convert
those to an unconditional skip, which is a no-op once a library
implements the feature and the manifest entry is removed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@rochdev rochdev changed the title perf(ffe): flush exposure writer instead of waiting on its periodic timer perf(ffe): fix FEATURE_FLAGGING_AND_EXPERIMENTATION CI regression on Node.js Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant