Skip to content

perf(stack): start independent eager services concurrently - #6809

Merged
jgoux merged 3 commits into
developfrom
perf/stack-concurrent-eager-startup
Sep 24, 2026
Merged

jgoux merged 3 commits into
developfrom
perf/stack-concurrent-eager-startup

Conversation

@jgoux

@jgoux jgoux commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Eager composition startup waits for each service to become healthy before starting the next, even when they are independent. Start independent branches concurrently and gate each dependent on readiness of its immediate prerequisites.

Preserve lazy route arming, lifecycle ownership and cancellation, ordered per-instance failure outcomes, and reverse-dependency shutdown. Report blocked dependents before preparing or launching them when a prerequisite fails.

Supabase service startup order

This is the actual dependency graph built by makeSupabaseComposition, shown with all services selected and configured as eager. Public endpoints are bound first. Each arrow means the source must be healthy before the target starts; a target with multiple incoming arrows waits for all of them.

flowchart LR
    subgraph roots["Start concurrently after endpoint binding"]
        db["PostgreSQL / database"]
        mail["Mail"]
        imgproxy["Imgproxy"]
        functions["Functions"]
    end

    db --> rest["REST / PostgREST"]
    db --> realtime["Realtime"]
    db --> pgmeta["pg-meta"]
    db --> analytics["Analytics"]
    db --> pooler["Pooler"]
    db --> auth["Auth"]
    mail --> auth
    db --> storage["Storage"]
    imgproxy --> storage

    pgmeta --> studio["Studio"]
    analytics --> studio
    functions --> studio
    analytics --> vector["Vector"]
Loading
  • At the start: PostgreSQL, Mail, Imgproxy, and Functions can prepare and launch concurrently.
  • Once PostgreSQL is healthy: REST, Realtime, pg-meta, Analytics, and Pooler can start concurrently. Auth can join as soon as Mail is also healthy; Storage can join as soon as Imgproxy is also healthy.
  • As those services become healthy: Vector starts after Analytics. Studio starts after pg-meta, Analytics, and Functions are all healthy. Neither waits for unrelated services to finish starting.

These are dependency constraints, not global startup phases: a ready branch advances immediately. Functions receives a database URL as configuration but has no database readiness dependency. Excluded services remove their corresponding managed edges.

With the default activation policy, PostgreSQL and services without public endpoints are eager; other services are lazy. Eager services pull in their prerequisites, while the remaining lazy services only arm their routes after their prerequisites settle and launch on demand. The diagram above shows the concurrency available when the complete graph is started eagerly.

@jgoux
jgoux requested a review from a team as a code owner September 24, 2026 19:16
@jgoux jgoux self-assigned this Sep 24, 2026

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

🤖 AI Review

All three reported findings are confirmed. The two orchestrator findings are minor polish issues; the defensive branch is unreachable in the current code. The test finding is a real timeout guard issue, although the integration suite has a 30-second outer timeout. I found no confirmed production behavior regression.

Findings

Severity Location Category Sources Claim
🟡 MINOR packages/stack/src/Orchestrator.integration.test.ts:393 test-robustness codex The lazy-service test can wait past its five-second observer timeout because it joins the observer again before checking the timeout result. The interruption test repeats the pattern.
⚪ NIT packages/stack/src/Orchestrator.ts:659 error-handling claude The defensive missing-completion branch returns a bare failure, bypassing the per-instance outcome wrapper if it ever runs.
⚪ NIT packages/stack/src/Orchestrator.ts:708 maintainability claude startComposition duplicates settle's failure aggregation and final observation logic, so changes to that result contract would require edits in both places.

Stats

Claude findings: 2 · Codex findings: 1 · Confirmed: 3 · Refuted: 0 · Uncertain: 0


Models: claude-opus-5-5 + gpt-6-sol · Trigger: auto · Workflow run

This review runs once per PR. A maintainer can request another with a /ai-review comment.

Comment thread packages/stack/src/Orchestrator.ts
Comment thread packages/stack/src/Orchestrator.ts Outdated
Comment thread packages/stack/src/Orchestrator.integration.test.ts Outdated

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

LGTM! non-blocking feedback below

One non-blocking suggestion inline about routing the new block through settle with a concurrency argument. It's a smaller version of the point the AI review raised on the now-resolved thread, and it also removes the only failure path that can bypass the per-instance outcomes wrapper.

Comment thread packages/stack/src/Orchestrator.ts Outdated
@jgoux
jgoux enabled auto-merge September 24, 2026 20:22
@jgoux
jgoux added this pull request to the merge queue Sep 24, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 24, 2026
@jgoux
jgoux added this pull request to the merge queue Sep 24, 2026
Merged via the queue into develop with commit 4cebcf8 Sep 24, 2026
29 checks passed
@jgoux
jgoux deleted the perf/stack-concurrent-eager-startup branch September 24, 2026 20:48
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