Skip to content

fix: block until provisioned database accepts connections - #84

Open
AmanVarshney01 wants to merge 1 commit into
mainfrom
fix/database-readiness-probe
Open

fix: block until provisioned database accepts connections#84
AmanVarshney01 wants to merge 1 commit into
mainfrom
fix/database-readiness-probe

Conversation

@AmanVarshney01

@AmanVarshney01 AmanVarshney01 commented Jul 19, 2026

Copy link
Copy Markdown
Member

Problem

createDatabaseCore returns the connection string the moment api.prisma.io/v1/projects responds (the create-db worker is a verbatim pass-through), with no readiness gate anywhere in the stack. A freshly provisioned database can briefly reject connections, so consumers that connect immediately race provisioning — create-prisma currently works around this with a blind 2s sleep before running the first prisma migrate dev.

Fix

Probe the direct TCP connection string with SELECT 1 (via @prisma/ppg, 500ms backoff, 30s cap) inside createDatabaseCore before returning. This is the single choke point, so every consumer path benefits: --json, --quiet, --env, interactive, and the programmatic create() export.

  • Non-fatal on timeout: callers still get their connection string, plus an additive ready?: boolean on the result.
  • Non-TCP (prisma+postgres://) URLs are skipped rather than probed.
  • Verified @prisma/ppg leaves no open handles: process exits cleanly after the probe under both Node 24 and Bun 1.3.

Cost

When the database is already reachable the probe is one query round trip — measured ~0.5–1s (to ap-southeast-1). It only waits when the database genuinely isn't accepting connections yet, i.e. exactly when returning early would hand out a broken URL. If the added latency is a concern for bare npx create-db usage, a --no-wait flag would be an easy follow-up — happy to add it.

Honesty note on reproduction

In 5 fresh provisions today the database answered on the first attempt (ready: true, no retries), so the race is rare/intermittent — this gate is cheap insurance that also lets create-prisma delete its unconditional 2s sleep (net faster for that flow).

Testing

  • pnpm typecheck, pnpm build clean
  • All 64 vitest tests pass (the creation tests exercise the probe against real databases)
  • Live run of the built CLI: node dist/cli.mjs --json"ready": true with normal wall-clock time

Summary by CodeRabbit

  • New Features
    • Added a database readiness probe after provisioning (when a direct Postgres connection string is available) to verify the database accepts a test query.
    • Results now include a ready flag indicating whether the readiness check succeeded.
    • Readiness checks retry until a timeout and then complete gracefully (instead of failing with an error).

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 19, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
create-db-worker 9ef091d Jul 19 2026, 10:23 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 19, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
claim-db-worker 9ef091d Jul 19 2026, 10:23 PM

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 332d18a9-4f8d-492d-aee0-b32136c18cd2

📥 Commits

Reviewing files that changed from the base of the PR and between cf01e11 and 9ef091d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • packages/create-db/package.json
  • packages/create-db/src/core/database.ts
  • packages/create-db/src/types.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/create-db/src/types.ts
  • packages/create-db/package.json
  • packages/create-db/src/core/database.ts

Walkthrough

create-db now probes direct TCP Postgres databases with retrying SELECT 1 queries and returns a ready boolean. The result type includes this field, and @prisma/ppg is added as a runtime dependency.

Changes

Database readiness reporting

Layer / File(s) Summary
Readiness result contract
packages/create-db/src/types.ts
DatabaseResult adds an optional ready field for readiness results.
Readiness probe integration
packages/create-db/package.json, packages/create-db/src/core/database.ts
Adds @prisma/ppg, retries SELECT 1 for direct TCP Postgres URLs, defaults readiness to false without a connection string, and includes ready in successful results.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: waiting for the database to accept connections before returning.
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.

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

@github-actions

Copy link
Copy Markdown

Preview CLIs & Workers are live!

Test the CLIs locally under tag pr84-fix-database-readiness-probe-29705661362:

npx create-db@pr84
npx create-pg@pr84
npx create-postgres@pr84

Worker URLs
• Create-DB Worker: https://create-db-temp.prisma.io
• Claim-DB Worker: https://create-db.prisma.io

These will live as long as this PR exists under tag pr84-fix-database-readiness-probe-29705661362.

@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: 2

🤖 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 `@packages/create-db/src/core/database.ts`:
- Around line 20-23: Update waitForDatabaseReady so skipped probes return
undefined rather than true for unsupported or pooled URLs, and when
connectionString is missing, distinguishing “not probed” from a failed readiness
check. Preserve true/false results for URLs that are actually probed, and update
callers to handle the undefined result without treating it as ready or timed
out.
- Around line 25-34: Update the readiness retry loop around the ppg.sql probe
and collect call to cap the retry delay at the remaining deadline, avoiding a
fixed 500ms sleep after the budget is nearly exhausted. Preserve successful
probes, and ensure the function returns false once the deadline is reached; if a
hard cutoff is needed, add an outer timeout around the stalled collect
operation.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 28fb0893-5b72-4825-8b2b-f4d74ca3613f

📥 Commits

Reviewing files that changed from the base of the PR and between f83cb32 and cf01e11.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • packages/create-db/package.json
  • packages/create-db/src/core/database.ts
  • packages/create-db/src/types.ts

Comment thread packages/create-db/src/core/database.ts Outdated
Comment on lines +20 to +23
// Only direct TCP URLs can be probed with @prisma/ppg.
if (!/^postgres(ql)?:\/\//.test(connectionString)) {
return true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

git ls-files 'packages/create-db/src/core/database.ts' 'packages/create-db/src/core/*' 'packages/create-db/src/**' | sed -n '1,120p'
echo '--- outline ---'
ast-grep outline packages/create-db/src/core/database.ts --view expanded || true
echo '--- lines 1-260 ---'
sed -n '1,260p' packages/create-db/src/core/database.ts
echo '--- search ready/usages ---'
rg -n "\bready\b|createDatabaseCore|probe" packages/create-db/src -S

Repository: prisma/create-db

Length of output: 7139


Don't encode skipped probes as ready: true.

waitForDatabaseReady() returns true for any non-postgres:// URL, so a pooled prisma+postgres:// connection is marked ready even though no probe ran. It also returns false when connectionString is missing, which conflates “not probed” with “timed out”. Return undefined for skipped probes, or split the result into “probed” and “ready”.

🤖 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 `@packages/create-db/src/core/database.ts` around lines 20 - 23, Update
waitForDatabaseReady so skipped probes return undefined rather than true for
unsupported or pooled URLs, and when connectionString is missing, distinguishing
“not probed” from a failed readiness check. Preserve true/false results for URLs
that are actually probed, and update callers to handle the undefined result
without treating it as ready or timed out.

Source: MCP tools

Comment on lines +25 to +34
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
try {
const ppg = prismaPostgres(defaultClientConfig(connectionString));
await ppg.sql`SELECT 1`.collect();
return true;
} catch {
await new Promise((resolve) =>
setTimeout(resolve, READINESS_RETRY_DELAY_MS)
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map relevant files
git ls-files 'packages/create-db/**' | sed -n '1,200p'

printf '\n--- database.ts ---\n'
wc -l packages/create-db/src/core/database.ts
cat -n packages/create-db/src/core/database.ts

printf '\n--- search for timeout/abort helpers ---\n'
rg -n "AbortController|abort|timeout|READINESS_RETRY_DELAY_MS|collect\\(\\)|prismaPostgres|SELECT 1" packages/create-db -S

Repository: prisma/create-db

Length of output: 9717


🌐 Web query:

@prisma/ppg AbortController timeout collect prismaPostgres sql timeout abort signal

💡 Result:

As of July 2026, the @prisma/ppg (Prisma Postgres serverless driver) library does not natively support AbortController or AbortSignal for canceling database queries [1][2][3]. While AbortController is a widely adopted standard in Node.js and web environments for cancelling asynchronous operations, it is not currently integrated into the @prisma/ppg query execution flow [4][5][6]. Consequently, there is no mechanism to pass an AbortSignal to the client's sql, query, or exec methods to terminate a long-running database request before it finishes [2][3]. Regarding timeouts and query management: - Query Timeouts: Prisma Postgres enforces internal timeouts depending on the connection type [7][8]. For pooled connections (common for application traffic), there is a 10-minute query timeout [8]. When using direct connections, specific, shorter timeouts apply (e.g., up to 10 seconds for standard queries, 15 seconds for interactive transactions) [7]. - Client Limitations: The @prisma/ppg client is designed for HTTP and WebSocket-based communication [1][8]. Because it manages its own transport layer, users cannot manually implement AbortController at the driver level to "force" the cancellation of a network request sent through this client [2][3]. If your use case requires preventing long-running operations from consuming resources, you must rely on server-side configuration and the inherent timeout limits enforced by the Prisma Postgres infrastructure rather than client-side signals [7][8]. [1][4][2][3][7][8]

Citations:


🌐 Web query:

@prisma/ppg defaultClientConfig timeout query cancellation direct connection options

💡 Result:

The @prisma/ppg library (also known as the Prisma Postgres serverless driver) is designed for serverless and edge environments, communicating via HTTP and WebSockets rather than the standard PostgreSQL TCP wire protocol [1][2][3]. Regarding your specific configuration and features: 1. defaultClientConfig: This function is used to initialize the client configuration, typically with the Prisma Postgres Direct TCP URL [1][4][5]. It automatically includes essential type parsers and serializers (for types like Date, JSON, and BigInt) [4][5]. Usage typically looks like this: const ppg = prismaPostgres(defaultClientConfig(process.env.PRISMA_DIRECT_TCP_URL!)); 2. Timeout and Query Cancellation: The @prisma/ppg driver itself does not expose explicit configuration options for query-level timeouts or cancellation via a standard API (such as an AbortController signal) in the same manner as some other fetch-based libraries [1][4][5]. Prisma ORM generally manages its own timeouts separate from database drivers [6][7]. For long-running queries in Prisma Postgres environments, be aware that pooled connections enforce a 10-minute timeout [2][8]. If your workload requires longer execution times or complex session states, you must use a direct connection, which bypasses the pooler [2][8]. 3. Direct Connection Options: While @prisma/ppg requires a "Direct TCP Connection" URL, it is important to clarify that this is used for routing and identification [1][2]. The transport remains HTTP/WebSocket [2]. If you are performing operations that require a true TCP-based direct connection—such as migrations, introspection, or specific session-level commands like LISTEN/NOTIFY—you should use the standard Prisma Client with the appropriate driver adapter (e.g., @prisma/adapter-pg) rather than the @prisma/ppg serverless driver [2][3][8]. In summary, @prisma/ppg is optimized for serverless performance and automatic connection pooling; if you find yourself needing low-level manual timeout controls or native TCP features, you are likely looking for the standard Prisma driver adapter approach instead [2][6][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for tests or call sites that rely on the readiness timeout behavior.
rg -n "waitForDatabaseReady|ready:\s*|READINESS_TIMEOUT_MS|createDatabaseCore\(" packages/create-db -S

Repository: prisma/create-db

Length of output: 643


Treat this as a soft deadline. @prisma/ppg doesn’t expose query cancellation, so a stalled collect() can run past 30s and the fixed 500ms backoff can add extra delay. Cap the sleep to the remaining budget, and if a hard cutoff is required, wrap the probe in an outer timeout and return false when it expires.

🤖 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 `@packages/create-db/src/core/database.ts` around lines 25 - 34, Update the
readiness retry loop around the ppg.sql probe and collect call to cap the retry
delay at the remaining deadline, avoiding a fixed 500ms sleep after the budget
is nearly exhausted. Preserve successful probes, and ensure the function returns
false once the deadline is reached; if a hard cutoff is needed, add an outer
timeout around the stalled collect operation.

A freshly created database could be returned to callers before it accepted
connections, so consumers that connect immediately (e.g. create-prisma
running the first migration) raced provisioning and sometimes failed.
create-prisma currently works around this with a blind 2s sleep.

Probe the direct TCP connection string with SELECT 1 (via @prisma/ppg,
500ms backoff, 30s cap) inside createDatabaseCore before returning, so
every consumer path (CLI flags and programmatic create()) gets a
connection string that is known to work. The probe is non-fatal on
timeout and surfaces an additive `ready` field on the result.

Measured cost when the database is already reachable: one query
round trip (~0.5-1s to ap-southeast-1).
@AmanVarshney01
AmanVarshney01 force-pushed the fix/database-readiness-probe branch from cf01e11 to 9ef091d Compare July 19, 2026 22:23
@github-actions

Copy link
Copy Markdown

Preview CLIs & Workers are live!

Test the CLIs locally under tag pr84-fix-database-readiness-probe-29706059153:

npx create-db@pr84
npx create-pg@pr84
npx create-postgres@pr84

Worker URLs
• Create-DB Worker: https://create-db-temp.prisma.io
• Claim-DB Worker: https://create-db.prisma.io

These will live as long as this PR exists under tag pr84-fix-database-readiness-probe-29706059153.

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