Skip to content

perf: reduce E2E CI runtime via parallel jobs and test tuning#420

Merged
moizpgedge merged 3 commits into
mainfrom
Feat/PLAT-660/Reduce-E2E-runtime-by-consolidating-or-using-parallelization
Jul 6, 2026
Merged

perf: reduce E2E CI runtime via parallel jobs and test tuning#420
moizpgedge merged 3 commits into
mainfrom
Feat/PLAT-660/Reduce-E2E-runtime-by-consolidating-or-using-parallelization

Conversation

@moizpgedge

@moizpgedge moizpgedge commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

PLAT-660 PR Summary

What this does

This PR makes the CI build much faster. It used to take about 44 minutes and now takes about 18 minutes. That is roughly 59 percent faster. The main idea was to run things at the same time instead of one after another, plus some smaller fixes to slow and flaky tests.

What changed

  1. The CI used to run everything in one big job. Now it runs in 3 separate jobs at the same time called Basic check 1, Basic check 2, and Basic check 3.

  2. Basic check 3 (the e2e tests) was the slowest part, so that job itself is now split across 3 machines running at the same time instead of one machine running everything.

  3. Some database tests were waiting on a slow setting called a checkpoint. Lowering that setting made one test almost 40 percent faster. We checked other tests too and found this trick only helps tests that add a replica to an already running database, not tests that create everything fresh, so we only applied it where it actually helps.

  4. Two tests that were doing similar setup work were combined into one test with two steps, since the setup itself was not the important part being tested.

  5. A few tests were flaky because they were not given enough time to finish under load. We gave them more time so they pass reliably instead of randomly failing and needing a retry.

  6. We also fixed a small bug in the Makefile where certain test filters would break if they included special characters.

How we tested it

We ran the full test suite locally against a real cluster and everything passed. We also triggered several real CI runs on this branch to confirm each change actually works, not just in theory. The final run showed all jobs passing in about 18 to 19 minutes.

Things to know

The Basic check 3 split relies on a CircleCI feature that only works inside their actual system, so it could only be tested by running it for real, not locally. The balance between its 3 machines will get better automatically over the next few runs as the system learns how long each test actually takes. Right now if Basic check 1 fails, the other two heavier jobs still run instead of stopping early. This uses a bit more compute time but keeps the speed benefit of running everything at once.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The CI workflow now splits unit, cluster, and E2E execution. E2E and service-update tests use shared test settings and subtests, cluster mode-change tests run in parallel, and the related docs and comments were updated.

Changes

CI and Test Workflow

Layer / File(s) Summary
Split CI test jobs
.circleci/config.yml, Makefile
Splits the workflow into unit_lint, test_cluster, and test_e2e, adds E2E test splitting, and writes JUnit output for test-e2e.

E2E Test Behavior

Layer / File(s) Summary
Apply checkpoint tuning to node specs
e2e/main_test.go, e2e/add_replica_test.go, e2e/db_create_test.go
Adds fastCheckpointConf and applies it to replica and create test node specs in the relevant requests.
Consolidate service add/remove tests
e2e/service_provisioning_test.go
Reworks database service updates into shared Add and Remove subtests and removes the standalone remove-service test.
Parallelize etcd mode change tests
clustertest/etcd_mode_change_test.go
Adds t.Parallel() to the client-to-server and server-to-client mode change tests.
Update test names and rationale comments
e2e/postgrest_test.go, docs/development/supported-services.md
Renames the documented service update test paths and adds comments explaining why the PostgREST preflight checks remain separate.

Poem

A rabbit split the test trail clear,
Fast hops for CI, no lingering fear.
Checkpoints blink, then settle low,
Subtests trim the service flow.
Hoppy builds now race with cheer. 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly matches the main change: parallelizing CI and tuning E2E tests to reduce runtime.
Description check ✅ Passed The description covers the summary, changes, testing, issue link, and reviewer notes, though it uses custom headings instead of the exact template.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch Feat/PLAT-660/Reduce-E2E-runtime-by-consolidating-or-using-parallelization

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@moizpgedge moizpgedge marked this pull request as draft July 2, 2026 05:53
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

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

🧹 Nitpick comments (5)
.circleci/config.yml (1)

74-87: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider adding failure-debug archiving to test_cluster, matching test_e2e.

test_e2e archives debug output and logs on failure (Lines 97-106), but test_cluster has no equivalent step, so cluster-test failures will be harder to diagnose from CI artifacts alone.

♻️ Proposed addition for debug parity
   test_cluster:
     executor: common
     steps:
       - common_setup
       - run:
           name: Run cluster tests
           command: |
             make docker-swarm-init
             make start-local-registry
             make buildx-init
             make test-cluster CONTROL_PLANE_IMAGE_REPO=172.17.0.1:5000/control-plane TEST_RERUN_FAILS=2
+      - store_artifacts:
+          path: <cluster-debug-output-dir>
       - store_test_results:
           path: .
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.circleci/config.yml around lines 74 - 87, Add failure-debug archiving to
the test_cluster job so it matches the debug behavior in test_e2e. Update the
test_cluster steps in the CircleCI config to include the same kind of on-failure
artifact collection used by the test_e2e job, placing it around the cluster test
run so CI retains logs/debug output when make test-cluster fails.
e2e/db_create_test.go (1)

65-68: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting the checkpoint conf literal to a shared test helper.

The same PostgresqlConf map (checkpoint_timeout: "30s", checkpoint_completion_target: "0") is duplicated here and twice more in e2e/add_replica_test.go. A shared helper/var reduces risk of the values drifting between call sites, since tests likely depend on identical checkpoint tuning to make replication assertions reliably fast.

♻️ Proposed refactor (e.g., in a shared e2e helpers file)
+var fastCheckpointConf = map[string]any{
+	"checkpoint_timeout":           "30s",
+	"checkpoint_completion_target": "0",
+}

Then reference fastCheckpointConf at each call site instead of the inline literal.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/db_create_test.go` around lines 65 - 68, The checkpoint PostgresqlConf
literal is duplicated across this test and the replica tests, so extract it into
a shared e2e helper/variable and reuse it at each call site. Define a single
shared config such as fastCheckpointConf in the e2e helpers area, then update
the relevant setup in db_create_test.go and add_replica_test.go to reference
that shared value instead of inline maps. Keep the values identical everywhere
so the test tuning stays consistent.
e2e/add_replica_test.go (1)

41-48: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate checkpoint conf literal between create and update requests.

Same concern as db_create_test.go: the identical PostgresqlConf map is repeated in the initial create (lines 41-48) and the update request (lines 88-91). Keeping the create/update specs in sync is intentional here (declarative spec), but a shared constant/var would make that intent explicit and prevent accidental divergence during future edits.

Also applies to: 88-91

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/add_replica_test.go` around lines 41 - 48, The same PostgresqlConf
literal is duplicated between the initial create and the later update request in
the add replica test, so make the shared checkpoint settings explicit by
extracting them into a single named constant or variable and reusing it in both
request specs. Update the create/update blocks in the test around the replica
spec so they both reference that shared definition, keeping the declarative
intent clear and preventing future divergence.
e2e/service_provisioning_test.go (2)

305-306: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove leftover commented-out code.

//Version: "1.0.0", is a dead debug artifact next to the active Version: "latest".

🧹 Cleanup
-						//Version:     "1.0.0",
 						Version: "latest",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/service_provisioning_test.go` around lines 305 - 306, Remove the leftover
commented-out Version assignment next to the active Version field in the
provisioning test setup; the commented `Version: "1.0.0",` is dead code and
should be deleted so the struct literal around the active `Version: "latest"`
stays clean.

252-360: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate DatabaseSpec literal across create/Add/Remove.

The same DatabaseSpec fields (name, users, port, nodes) are repeated three times, differing only in Services. postgrest_test.go already solves this with a postgrestBaseSpec helper — consider the same pattern here to keep future spec changes (e.g. new required fields) in sync across all three call sites.

♻️ Example refactor
func updateDatabaseServiceSpec(host1 string, services []*controlplane.ServiceSpec) *controlplane.DatabaseSpec {
	return &controlplane.DatabaseSpec{
		DatabaseName: "test_update_database_service",
		DatabaseUsers: []*controlplane.DatabaseUserSpec{
			{
				Username:   "admin",
				Password:   pointerTo("testpassword"),
				DbOwner:    pointerTo(true),
				Attributes: []string{"LOGIN", "SUPERUSER"},
			},
		},
		Port:        pointerTo(0),
		PatroniPort: pointerTo(0),
		Nodes: []*controlplane.DatabaseNodeSpec{
			{
				Name:    "n1",
				HostIds: []controlplane.Identifier{controlplane.Identifier(host1)},
			},
		},
		Services: services,
	}
}

Then callers become Spec: updateDatabaseServiceSpec(host1, nil), Spec: updateDatabaseServiceSpec(host1, []*controlplane.ServiceSpec{...}), and Spec: updateDatabaseServiceSpec(host1, []*controlplane.ServiceSpec{}).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/service_provisioning_test.go` around lines 252 - 360, The same
DatabaseSpec setup is duplicated in the create, Add, and Remove paths, so future
schema changes will be easy to miss. Extract the repeated database fields into a
helper like updateDatabaseServiceSpec and have the existing
CreateDatabaseRequest and db.Update calls reuse it, varying only the Services
argument. Use the existing database test setup around db.Update,
CreateDatabaseRequest, and ServiceSpec to keep the spec consistent in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.circleci/config.yml:
- Around line 74-87: Add failure-debug archiving to the test_cluster job so it
matches the debug behavior in test_e2e. Update the test_cluster steps in the
CircleCI config to include the same kind of on-failure artifact collection used
by the test_e2e job, placing it around the cluster test run so CI retains
logs/debug output when make test-cluster fails.

In `@e2e/add_replica_test.go`:
- Around line 41-48: The same PostgresqlConf literal is duplicated between the
initial create and the later update request in the add replica test, so make the
shared checkpoint settings explicit by extracting them into a single named
constant or variable and reusing it in both request specs. Update the
create/update blocks in the test around the replica spec so they both reference
that shared definition, keeping the declarative intent clear and preventing
future divergence.

In `@e2e/db_create_test.go`:
- Around line 65-68: The checkpoint PostgresqlConf literal is duplicated across
this test and the replica tests, so extract it into a shared e2e helper/variable
and reuse it at each call site. Define a single shared config such as
fastCheckpointConf in the e2e helpers area, then update the relevant setup in
db_create_test.go and add_replica_test.go to reference that shared value instead
of inline maps. Keep the values identical everywhere so the test tuning stays
consistent.

In `@e2e/service_provisioning_test.go`:
- Around line 305-306: Remove the leftover commented-out Version assignment next
to the active Version field in the provisioning test setup; the commented
`Version: "1.0.0",` is dead code and should be deleted so the struct literal
around the active `Version: "latest"` stays clean.
- Around line 252-360: The same DatabaseSpec setup is duplicated in the create,
Add, and Remove paths, so future schema changes will be easy to miss. Extract
the repeated database fields into a helper like updateDatabaseServiceSpec and
have the existing CreateDatabaseRequest and db.Update calls reuse it, varying
only the Services argument. Use the existing database test setup around
db.Update, CreateDatabaseRequest, and ServiceSpec to keep the spec consistent in
one place.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 215e7ad3-043a-4600-b3ae-c03869f3a14e

📥 Commits

Reviewing files that changed from the base of the PR and between 327710a and 00cadb2.

📒 Files selected for processing (5)
  • .circleci/config.yml
  • e2e/add_replica_test.go
  • e2e/db_create_test.go
  • e2e/postgrest_test.go
  • e2e/service_provisioning_test.go

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
.circleci/config.yml (1)

93-97: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated go/install + set_gopath + attach_workspace boilerplate across three jobs.

unit_lint, test_cluster, and test_e2e each repeat the identical 3-step sequence (plus common_setup also pins the same Go version), so the Go version now appears hardcoded in 4 places. Consider extracting a shared command (e.g. attach_project) to avoid version drift when bumping Go.

♻️ Suggested consolidation
+  attach_project:
+    steps:
+      - go/install:
+          version: '1.25.8'
+      - set_gopath
+      - attach_workspace:
+          at: /home/circleci

Then in each job:

   unit_lint:
     executor: common
     steps:
-      - go/install:
-          version: '1.25.8'
-      - set_gopath
-      - attach_workspace:
-          at: /home/circleci
+      - attach_project

(repeat similarly for test_cluster and test_e2e)

Also applies to: 107-111, 126-130

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.circleci/config.yml around lines 93 - 97, The setup for `unit_lint`,
`test_cluster`, and `test_e2e` repeats the same `go/install`, `set_gopath`, and
`attach_workspace` sequence, and `common_setup` hardcodes the same Go version
too. Extract that repeated bootstrap into a shared CircleCI command or reusable
step (for example, an `attach_project` command) and have each job invoke it, so
the Go version and workspace setup are defined in one place and stay in sync.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.circleci/config.yml:
- Around line 44-52: The Go workspace path is inconsistent between the setup
cache/workspace and the GOPATH export, so downstream jobs won’t reuse the same
downloaded modules and installed tools. Update the CircleCI config so the
`persist_to_workspace` path, `use_mod_cache`, and `set_gopath`/`GOPATH` all
reference the same workspace directory, keeping the `go_workspace` path
consistent across jobs.

---

Nitpick comments:
In @.circleci/config.yml:
- Around line 93-97: The setup for `unit_lint`, `test_cluster`, and `test_e2e`
repeats the same `go/install`, `set_gopath`, and `attach_workspace` sequence,
and `common_setup` hardcodes the same Go version too. Extract that repeated
bootstrap into a shared CircleCI command or reusable step (for example, an
`attach_project` command) and have each job invoke it, so the Go version and
workspace setup are defined in one place and stay in sync.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ff903f68-23ad-465d-b4b7-0b1874e94c0d

📥 Commits

Reviewing files that changed from the base of the PR and between d8d49c6 and 6d59294.

📒 Files selected for processing (1)
  • .circleci/config.yml

Comment thread .circleci/config.yml Outdated
Comment on lines +44 to +52
- run:
# GOPATH must be explicit and identical across every job so that
# go_workspace/pkg/mod and go_workspace/bin (persisted from the
# setup job) resolve to the same paths the tools were installed
# to and the modules were downloaded to. Without this, GOPATH
# defaults to whatever the machine image's ambient default is,
# which may not match the persisted workspace paths.
name: Set GOPATH
command: echo 'export GOPATH=/home/circleci/.go_workspace' >> $BASH_ENV

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check for other/prior references to go_workspace / .go_workspace to confirm the canonical directory name.
rg -n 'go_workspace|GOPATH' .circleci/config.yml

Repository: pgEdge/control-plane

Length of output: 689


🏁 Script executed:

#!/bin/bash
sed -n '30,95p' .circleci/config.yml

Repository: pgEdge/control-plane

Length of output: 2246


🏁 Script executed:

#!/bin/bash
sed -n '1,220p' .circleci/config.yml

Repository: pgEdge/control-plane

Length of output: 6831


Align the Go workspace paths across cache, workspace, and GOPATH. persist_to_workspace restores go_workspace/..., but use_mod_cache and set_gopath point at /home/circleci/.go_workspace/..., so the downstream jobs won’t reuse the modules/tools populated in setup. Use one directory name everywhere.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.circleci/config.yml around lines 44 - 52, The Go workspace path is
inconsistent between the setup cache/workspace and the GOPATH export, so
downstream jobs won’t reuse the same downloaded modules and installed tools.
Update the CircleCI config so the `persist_to_workspace` path, `use_mod_cache`,
and `set_gopath`/`GOPATH` all reference the same workspace directory, keeping
the `go_workspace` path consistent across jobs.

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
.circleci/config.yml (1)

88-90: 🧹 Nitpick | 🔵 Trivial

Combined parallelism (3 containers × E2E_PARALLEL=4) may increase contention.

Each of the 3 parallel containers additionally runs 4 concurrent Go test workers (E2E_PARALLEL=4), for up to 12 concurrent e2e test executions total across the workflow. If e2e tests share limited local resources (ports, docker-compose network/volumes) within a container this is fine since compose stacks are per-container, but worth a sanity check that no shared external service (e.g. a shared registry, DB, or rate-limited endpoint) is contended by all 3 containers simultaneously.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.circleci/config.yml around lines 88 - 90, The test_e2e job is running with
both CircleCI parallelism and E2E_PARALLEL, which multiplies total concurrent
e2e load and may contend on shared external resources. Review the test_e2e
configuration in .circleci/config.yml and either reduce parallelism or make the
e2e setup isolate any shared dependencies; check the executor/common job setup
and the E2E_PARALLEL usage together so the total concurrency stays safe for any
registry, DB, or rate-limited endpoint.
Makefile (1)

122-132: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the duplicate --junitfile here. gotestsum already adds --junitfile $@-results.xml in CI, so this target passes the same flag twice in CircleCI. Drop the explicit flag to avoid redundant CLI args.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 122 - 132, The test-e2e target in Makefile is passing
a duplicate --junitfile flag because gotestsum already injects the results file
in CI. Remove the explicit --junitfile option from the test-e2e recipe and keep
the rest of the gotestsum invocation unchanged so the target no longer forwards
the same CLI argument twice.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.circleci/config.yml:
- Around line 88-115: The e2e test selection step can fail before the skip check
when circleci tests split returns no files, because the TEST_FILES/TEST_NAMES
pipeline in the test_e2e job runs under bash -eo pipefail. Update the “Select
this container's e2e tests” run block to handle the empty split case first, and
only build E2E_RUN from TEST_NAMES when TEST_FILES is non-empty; otherwise leave
TEST_NAMES empty so the later “Run e2e tests with Docker Compose” step can
safely skip. Use the existing TEST_FILES, TEST_NAMES, and E2E_RUN logic in
.circleci/config.yml as the place to apply the guard.

---

Nitpick comments:
In @.circleci/config.yml:
- Around line 88-90: The test_e2e job is running with both CircleCI parallelism
and E2E_PARALLEL, which multiplies total concurrent e2e load and may contend on
shared external resources. Review the test_e2e configuration in
.circleci/config.yml and either reduce parallelism or make the e2e setup isolate
any shared dependencies; check the executor/common job setup and the
E2E_PARALLEL usage together so the total concurrency stays safe for any
registry, DB, or rate-limited endpoint.

In `@Makefile`:
- Around line 122-132: The test-e2e target in Makefile is passing a duplicate
--junitfile flag because gotestsum already injects the results file in CI.
Remove the explicit --junitfile option from the test-e2e recipe and keep the
rest of the gotestsum invocation unchanged so the target no longer forwards the
same CLI argument twice.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: da27184d-0bc7-4a89-8ad1-eeb25e689527

📥 Commits

Reviewing files that changed from the base of the PR and between c7131c0 and 24246fe.

📒 Files selected for processing (2)
  • .circleci/config.yml
  • Makefile

Comment thread .circleci/config.yml
Split the monolithic CircleCI test job into 3 concurrent jobs
(unit_lint, test_cluster, test_e2e), then split test_e2e itself
across 3 parallel containers using circleci tests split. Total
CI wall-clock dropped from ~44min to ~18min (~59% reduction).

Also:
- Tune checkpoint_timeout/checkpoint_completion_target for tests
  that add a replica, cutting TestAddReplica's runtime by ~37%
  (measured: 276s -> 173s).
- Consolidate TestUpdateDatabaseAddService/RemoveService into one
  test with Add/Remove subtests sharing a database, since the
  update behavior (not creation) is what's under test.
- Fix flaky-test timeouts: spock.wait_for_sync_event and WAL-replay
  poll windows were too tight under CI load; the post-host-removal
  sleep and host-count wait in TestForcedHostRemovalWithDatabase
  were similarly tight.
- Add JUnit output to test-e2e so circleci tests split can balance
  containers by historical timing instead of file count.

PLAT-660
@moizpgedge moizpgedge force-pushed the Feat/PLAT-660/Reduce-E2E-runtime-by-consolidating-or-using-parallelization branch from 3f729e7 to 35f883a Compare July 2, 2026 14:41
@moizpgedge moizpgedge changed the title ci: parallelize CI jobs and speed up e2e tests perf: reduce E2E CI runtime via parallel jobs and test tuning Jul 2, 2026
@moizpgedge moizpgedge marked this pull request as ready for review July 2, 2026 15:51

@jason-lynch jason-lynch left a comment

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.

Nice work! This looks like a huge improvement. Sorry for the confusion around the job names - I was only suggesting basic_check as an alternative for the make ci job because it's doing several different types of tests and checks. I also have one very small suggestion in the Makefile, but otherwise, this looks really great!

Comment thread .circleci/config.yml Outdated
jobs:
test:
# basic_check_1: unit tests + lint + license check (make ci)
basic_check_1:

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.

I think the name basic_check without the _1 makes sense here. What do you think?

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.

Changed this to basic_check
because other are renamed.

Comment thread .circleci/config.yml Outdated
path: .

# basic_check_2: multi-host cluster integration tests (clustertest/)
basic_check_2:

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.

I thought your original name, test_cluster was appropriate here, since this is for the make test-cluster target.

Comment thread .circleci/config.yml Outdated
path: .

# basic_check_3: end-to-end tests (e2e/), split across 3 parallel containers
basic_check_3:

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.

I think your original name, test_e2e was a better fit.

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.

sure i can change it

Comment thread Makefile Outdated
$(gotestsum) \
--format-hide-empty-pkg \
--format standard-verbose \
--junitfile test-e2e-results.xml \

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.

I don't think this change is necessary. We automatically add the --junitfile argument on line 62 where we set gotestsum. If you look in the log output from the latest CircleCI run, you'll see that this argument is getting set twice now:

/home/circleci/.go_workspace/bin/gotestsum --junitfile test-e2e-results.xml \
        --format-hide-empty-pkg \
        --format standard-verbose \
        --junitfile test-e2e-results.xml \
        --rerun-fails=2 \
        --rerun-fails-max-failures=4 \
        --packages='./e2e/...' \
        -- \
        -tags=e2e_test -count=1 -timeout=45m -parallel 4 -run "^(TestAddNodeOriginAdvanced|TestCancelDatabaseTask|TestUpdateAddNode23|TestUpdateAddNode12|TestMinorVersionUpgrade|TestPortChange|TestScripts|TestWholeCluster)$" -args -fixture ci  -debug

Rename basic_check_1/2/3 back to basic_check/test_cluster/test_e2e
per review - the numbered generic names lost the descriptive
mapping to their make targets. Also remove the explicit
--junitfile flag in test-e2e, since the gotestsum variable already
adds it automatically for CI runs and it was being set twice.

PLAT-660
@moizpgedge moizpgedge merged commit eb4c4b6 into main Jul 6, 2026
5 checks passed
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