Skip to content

perf(nodejs): move the ingestion e2e suite to the parallel lane - #90032

Open
jose-sequeira wants to merge 6 commits into
masterfrom
jose-sequeira/e2e-global-setup
Open

perf(nodejs): move the ingestion e2e suite to the parallel lane#90032
jose-sequeira wants to merge 6 commits into
masterfrom
jose-sequeira/e2e-global-setup

Conversation

@jose-sequeira

@jose-sequeira jose-sequeira commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Problem

Anyone waiting on Node.js CI pays for ingestion-e2e in the serial lane, where it is the single largest file (about 124 s of the roughly 550 s of serial work after #89152). Moving it to the parallel lane, with its tests running concurrently, cuts the slowest serial shard by about half.

The move alone is flaky on a fresh broker, and #89866 handles that with a startup retry in the production checkTopics. This PR takes the same move without touching production code, because the cause is in the test harness:

  • jest-circus starts every test.concurrent body at the root block as soon as a nested beforeAll hits its first await.
  • The e2e suites create their Kafka topics and wait for the ClickHouse Kafka engine inside a beforeAll nested in describe.each.
  • The first maxConcurrency tests therefore start their consumer while ensureKafkaTopics is still creating topics, and the startup topic check fails on whichever topics are not there yet.
  • Those tests also ran before waitForClickHouseKafkaConsumer returned, so even a passing topic check could lose events to a not-yet-assigned ClickHouse consumer.

Changes

  • The slowest serial shard drops from about 263 s to about 134 s, because ingestion-e2e now runs in the parallel lane with its 152 tests concurrent.
  • The e2e suites no longer race their own setup: createTestWithTeamIngester awaits a memoized ensureIngestionE2EInfraReady() inside every concurrent test, so topics and the ClickHouse consumer are ready before any consumer starts, regardless of hook placement.
  • Concurrent e2e tests overlap more: the parallel-lane Jest config sets maxConcurrency: 15 (Jest default 5). The setting only affects test.concurrent bodies, which exist only in the shared harness. Those tests are wait-bound on ClickHouse's 500 ms Kafka engine flush, so more in flight halves ingestion-e2e locally (31 s to 16 s).
  • person-updates-e2e runs on the same harness, so its 88 tests run concurrently instead of one at a time through module-level state (20 s to 5 s locally). Its bodies are unchanged; the diff is prettier re-indenting them inside the harness call.
  • The five ingestion e2e suites call the readiness helper from beforeAll instead of carrying their own copy of the setup (mechanical).
  • Nothing user-visible changes. Test infrastructure only.

Note

The first two commits are #89866's rename and test.concurrent change, taken as-is. This PR replaces the checkTopics retry in that PR with the harness fix, so only one of the two should merge.

How did you test this code?

  • Reproduced the failure locally on the perf(nodejs): run the ingestion e2e suite concurrently #89866 head by adding a not-yet-created probe output topic and padding topic creation to match a cold broker: the first two tests in file order failed with Output topic verification failed for: tophog, with the retry disabled.
  • With the harness gate and no retry, the same reproduction passed three times in a row (152 tests).
  • Instrumented the harness per phase: createIngestionTestInfra is under 1% of ingestion-e2e (0.5 s across 152 tests), test bodies are 85%. That is why the change raises concurrency rather than sharing infra.
  • maxConcurrency sweep locally: 5 → 31 s, 15 → 16 s, 30 → 12 s for ingestion-e2e; 15 chosen as a first step. Three runs at 15 with all harness suites together passed.
  • person-updates-e2e before and after the port, two runs each: 20.4 s / 19.3 s → 5.3 s / 4.3 s, 88 tests both ways.
  • flag-evaluations-e2e fails one assertion locally on the untouched perf(nodejs): run the ingestion e2e suite concurrently #89866 head as well (local ClickHouse flag_evaluations schema) and passes in CI.
  • Not run: hogli review (the Greptile CLI does not install in this environment) and the full Node.js suite.

Automatic notifications

  • Publish to changelog?

Docs update

None.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Claude Code (Claude Fable 5) under @jose-sequeira's direction, starting from a review of #89866. Skills invoked: /writing-pr-descriptions, /writing-tests. The mechanism was confirmed against the installed jest-circus 30.0.5 source and against the failing-test pattern on #89152's branch (always the first five tests in file order). The branch was first stacked on #89866 and then rebuilt on master without the retry commits, at the reviewer's request. Sharing createIngestionTestInfra across tests was measured and rejected as a non-lever before the concurrency change was made.

@jose-sequeira jose-sequeira self-assigned this Aug 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🤖 CI report

Trunk lane — non-backend lane

This PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes.

@trunk-io

trunk-io Bot commented Aug 27, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

@jose-sequeira
jose-sequeira force-pushed the jose-sequeira/e2e-global-setup branch from 001251b to e7e1121 Compare August 27, 2026 12:06
@jose-sequeira jose-sequeira changed the title chore(nodejs): gate concurrent e2e tests on shared infra readiness perf(nodejs): move the ingestion e2e suite to the parallel lane Aug 27, 2026
@jose-sequeira
jose-sequeira changed the base branch from nodejs-ingestion-topic-check-retry to master August 27, 2026 12:07
@trunk-io

trunk-io Bot commented Aug 27, 2026

Copy link
Copy Markdown

Merging to master in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@jose-sequeira
jose-sequeira marked this pull request as ready for review August 27, 2026 12:59
@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team August 27, 2026 13:00
@greptile-apps

greptile-apps Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
### Issue 1
nodejs/tests/helpers/ingestion-e2e.ts:528-529
**Concurrent tests share handlers**

When the two client-warnings cases run concurrently, each consumer connection overwrites the same module-scoped `mockCapturedHandler`, so a test can dispatch its batch through the other test's pipeline and dependencies, causing missing or unexpected ClickHouse rows and nondeterministic CI failures.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "Merge branch 'master' into jose-sequeira..." | Re-trigger Greptile

Comment on lines +528 to +529
test.concurrent(name, async () => {
await ensureIngestionE2EInfraReady()

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 Concurrent tests share handlers

When the two client-warnings cases run concurrently, each consumer connection overwrites the same module-scoped mockCapturedHandler, so a test can dispatch its batch through the other test's pipeline and dependencies, causing missing or unexpected ClickHouse rows and nondeterministic CI failures.

Prompt To Fix With AI
This is a comment left during a code review.
Path: nodejs/tests/helpers/ingestion-e2e.ts
Line: 528-529

Comment:
**Concurrent tests share handlers**

When the two client-warnings cases run concurrently, each consumer connection overwrites the same module-scoped `mockCapturedHandler`, so a test can dispatch its batch through the other test's pipeline and dependencies, causing missing or unexpected ClickHouse rows and nondeterministic CI failures.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

benjackwhite and others added 6 commits August 28, 2026 10:24
The retry above lets its startup topic check ride out a transient metadata
gap, which is what kept this suite on the serial lane. 152 tests, 29s on the
serial lane.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The tests are almost entirely idle, waiting on the ClickHouse Kafka engine to
flush, so overlapping them is most of the suite's runtime.

This needs the retry below. Each test builds its own KafkaProducerWrapper, so
concurrency churns a producer per test through the broker, and the startup
topic check used to fail on one absent metadata response.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jest-circus starts test.concurrent bodies at the root block as soon as a
nested beforeAll hits its first await. In the ingestion e2e suites that
beforeAll creates the output topics and waits for the ClickHouse Kafka
engine, so the first maxConcurrency tests raced topic creation and failed
their startup topic check with a random subset of topics.

Memoize the shared setup in the harness and await it inside every
concurrent test, so readiness no longer depends on hook placement. Add a
small test documenting the scheduling behavior.
…uites

The four other ingestion e2e suites carried the same nested beforeAll
setup. Route them through ensureIngestionE2EInfraReady so the setup lives
in one place and no suite depends on hook placement.
The harness's test.concurrent bodies are wait-bound on ClickHouse's Kafka
engine flush, not CPU-bound, so Jest's default of 5 in flight per worker
leaves most of the file idle. 15 halves ingestion-e2e locally (31 s to
16 s); instrumenting the harness showed per-test infra setup is under 1%
of the file, so sharing it would not have helped.
The suite already minted a team per test but ran them one at a time
through module-level state (currentToken, a per-describe ingester).
Porting it onto createTestWithTeamIngester removes that state and runs
the 88 tests concurrently: 20 s to 5 s locally.
@jose-sequeira
jose-sequeira force-pushed the jose-sequeira/e2e-global-setup branch from 0438e8a to ddb5497 Compare August 28, 2026 08:25
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.

2 participants