Skip to content

chore: adopt Prisma 7 beta (tsgo)#3813

Closed
deepshekhardas wants to merge 20 commits into
triggerdotdev:mainfrom
deepshekhardas:feat/prisma-7-upgrade
Closed

chore: adopt Prisma 7 beta (tsgo)#3813
deepshekhardas wants to merge 20 commits into
triggerdotdev:mainfrom
deepshekhardas:feat/prisma-7-upgrade

Conversation

@deepshekhardas
Copy link
Copy Markdown

Migrate Prisma from 6.14.0 to 7.7.0 with driver adapters. Closes #3391

Deploy Bot and others added 20 commits February 2, 2026 16:16
- Include reproduction scripts for Sentry (triggerdotdev#2900) and engine strictness (triggerdotdev#2913)
- Include PR body drafts for consolidated tracking
- Include reproduction scripts for Sentry (triggerdotdev#2900) and engine strictness (triggerdotdev#2913)
- Include PR body drafts for consolidated tracking
When the underlying logical-replication client errored (e.g. after a
Postgres failover), the runs and sessions replication services logged
the error and left the stream stopped. The host process kept running,
the WAL backed up, and ClickHouse silently fell behind.

Both services now run a configurable recovery strategy on stream errors,
defaulting to in-process reconnect with exponential backoff so a fresh
self-hosted setup heals on its own:

- "reconnect" (default) re-subscribes via the existing subscribe(lastLsn)
  path with exponential backoff (1s -> 60s cap, unlimited attempts), which
  re-validates the publication, re-acquires the leader lock, and resumes
  from the last acknowledged LSN.
- "exit" calls process.exit after a short flush window so a host's
  supervisor (Docker restart=always, systemd, k8s, etc.) can replace the
  process.
- "log" preserves the historical behaviour.

Per-service strategy + exit knobs are env-driven via
RUN_REPLICATION_ERROR_STRATEGY / SESSION_REPLICATION_ERROR_STRATEGY plus
matching *_EXIT_DELAY_MS / *_EXIT_CODE. Reconnect tuning is shared
across both services via REPLICATION_RECONNECT_INITIAL_DELAY_MS /
_MAX_DELAY_MS / _MAX_ATTEMPTS (0 = unlimited).
Addresses PR review feedback:

- LogicalReplicationClient.subscribe() can throw before its internal
  "error" listener is wired up (notably when pg client.connect() fails
  mid-failover). The reconnect strategy's catch block only logged, so
  recovery silently stopped. Now also calls scheduleReconnect(err) — the
  pendingReconnect guard makes it idempotent if an error event was also
  emitted.
- Reject negative values for the new replication-recovery env vars and
  cap exit codes at 255.
- Convert the new ReplicationErrorRecovery{Deps,} interfaces to type
  aliases to match the repo's TypeScript style.
- Tighten the reconnect dep comment to drop a stale "lastAcknowledgedLsn"
  reference (the wrapper-tracked resume LSN is what callers actually pass).
- Restore process.exit after service.shutdown() in the exit-strategy
  test so a delayed exit timer can't terminate the test worker.
LogicalReplicationClient.subscribe() can resolve without throwing or
emitting an "error" event when leader-lock acquisition fails — it just
calls this.stop() and returns. The reconnect callback now checks
isStopped after subscribe() and throws so the recovery handler can
schedule the next attempt instead of silently giving up.
…rough handle()

The previous post-subscribe() isStopped check was always true on the
happy path: subscribe() calls stop() up front (setting _isStopped=true)
and only resets the flag inside the replicationStart event, which fires
asynchronously after subscribe() returns. So the check threw on every
successful reconnect, the catch rescheduled, the next attempt tore down
the just-built client, and the cycle continued — replication briefly
worked between teardowns, which is why the integration test passed.

Replace it with the correct nudge: subscribe to leaderElection and call
the recovery handler on isLeader=false. That's the only subscribe()
exit path that doesn't either throw or emit an "error" event (the other
silent-return paths emit "error" first via createPublication/createSlot
failures).
The previous commit routed leaderElection(false) through handle(), which
under the exit strategy schedules process.exit. In a multi-instance
deployment that turns lost leader election — a normal operational state
— into a restart loop: exit, supervisor restarts, election fails again,
exit, and so on.

Add a dedicated notifyLeaderElectionLost() on ReplicationErrorRecovery
that the reconnect strategy treats as another retry trigger, while
exit and log strategies no-op. Wire the wrapper services through the
new method.
fix(webapp): auto-recover replication services after stream errors
…iggerdotdev#3391)

- Update schema.prisma for Prisma 7 compatibility
- Add prisma.config.ts with driver adapter setup
- Update transaction.ts for new Prisma client API
- Update docker/entrypoint.sh and Dockerfile for pnpm 10.23.0
- Update package.json across packages for Prisma 7 deps
- Update testcontainers, run-engine tests for new Prisma version
- Add references/prisma-7/package.json placeholder

Closes triggerdotdev#3391
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 3, 2026

🦋 Changeset detected

Latest commit: 5f4c41a

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 3, 2026

Hi @deepshekhardas, thanks for your interest in contributing!

This project requires that pull request authors are vouched, and you are not in the list of vouched users.

This PR will be closed automatically. See https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md for more details.

@github-actions github-actions Bot closed this Jun 3, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: eb214db7-4d5b-4652-acbd-9a83bd771045

📥 Commits

Reviewing files that changed from the base of the PR and between a9f756b and 5f4c41a.

⛔ Files ignored due to path filters (2)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • references/prisma-7/package.json is excluded by !references/**
📒 Files selected for processing (47)
  • .changeset/fix-console-interceptor-2900.md
  • .changeset/fix-docker-hub-rate-limit-2911.md
  • .changeset/fix-github-install-node-version-2913.md
  • .changeset/fix-orphaned-workers-2909.md
  • .changeset/fix-sentry-oom-2920.md
  • .server-changes/replication-error-recovery.md
  • apps/webapp/app/db.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/routes/metrics.ts
  • apps/webapp/app/services/replicationErrorRecovery.server.ts
  • apps/webapp/app/services/runsReplicationInstance.server.ts
  • apps/webapp/app/services/runsReplicationService.server.ts
  • apps/webapp/app/services/sessionsReplicationInstance.server.ts
  • apps/webapp/app/services/sessionsReplicationService.server.ts
  • apps/webapp/app/v3/tracer.server.ts
  • apps/webapp/package.json
  • apps/webapp/test/runsReplicationBenchmark.producer.ts
  • apps/webapp/test/runsReplicationService.errorRecovery.test.ts
  • consolidated_pr_body.md
  • docker/Dockerfile
  • docker/scripts/entrypoint.sh
  • internal-packages/database/package.json
  • internal-packages/database/prisma.config.ts
  • internal-packages/database/prisma/schema.prisma
  • internal-packages/database/src/transaction.ts
  • internal-packages/database/tsconfig.json
  • internal-packages/run-engine/src/engine/tests/priority.test.ts
  • internal-packages/run-engine/src/engine/tests/waitpoints.test.ts
  • internal-packages/testcontainers/package.json
  • internal-packages/testcontainers/src/index.ts
  • internal-packages/testcontainers/src/utils.ts
  • packages/cli-v3/src/cli/common.ts
  • packages/cli-v3/src/commands/deploy.ts
  • packages/cli-v3/src/commands/dev.ts
  • packages/cli-v3/src/commands/login.ts
  • packages/cli-v3/src/commands/update.test.ts
  • packages/cli-v3/src/commands/update.ts
  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/cli-v3/src/entryPoints/dev-run-worker.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/cli-v3/src/entryPoints/managed-run-worker.ts
  • packages/cli-v3/src/utilities/sourceMaps.test.ts
  • packages/cli-v3/src/utilities/sourceMaps.ts
  • packages/core/src/v3/consoleInterceptor.ts
  • scripts/recover-stuck-runs.ts
  • tests/utils.ts

Walkthrough

This PR upgrades Prisma from version 6.14.0 to 7.7.0 with adapter-based PostgreSQL connectivity, introduces configurable replication error recovery for critical services, adds flexible source-map support configuration, fixes console interceptor log-chain preservation, and implements CLI stability improvements. The changes span database connectivity patterns across all Prisma clients, new replication error recovery service with exponential-backoff reconnection, environment-variable-driven source maps utility, console method delegation, Docker Hub authentication for builds, engine-check bypassing during deployment, and proper SIGINT handling for dev process cleanup.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat/prisma-7-upgrade

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 and usage tips.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 4 potential issues.

View 5 additional findings in Devin Review.

Open in Devin Review

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.

🚩 Prisma metrics endpoint and OTEL metrics removed — observability gap

The PR removes Prisma's built-in $metrics.prometheus() from the /metrics endpoint (apps/webapp/app/routes/metrics.ts) and the entire configurePrismaMetrics function from apps/webapp/app/v3/tracer.server.ts. With PrismaPg, Prisma no longer exposes internal pool metrics (connections open/busy/idle, query wait times, etc.). The pg pool itself exposes pool.totalCount, pool.idleCount, pool.waitingCount via the Pool instance, but these are not wired up anywhere. Operators using Grafana dashboards that monitor db.pool.connections.* or prisma_* metrics will see all those series go to zero after this deploys.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@@ -260,8 +261,7 @@ export async function updateTriggerPackages(
await installDependencies({ cwd: projectPath, silent: true });
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.

🔴 ignoreEngines option declared but never passed to installDependencies

The ignoreEngines option was added to UpdateCommandOptions and is set to true in the deploy path (deploy.ts:262), but the actual installDependencies call at update.ts:261 never reads options.ignoreEngines and never passes engine-related args to installDependencies. The tests verify that args like ["--no-engine-strict"] are passed, but the implementation just calls installDependencies({ cwd: projectPath, silent: true }) with no args field. This means the stated fix — "Ignore engine checks during deployment install phase to prevent failure on build server when Node version mismatch exists" — has no effect at runtime.

Prompt for agents
The ignoreEngines option is added to CommonCommandOptions and passed from deploy.ts, but updateTriggerPackages in update.ts never uses it. The installDependencies call at line 261 needs to compute engine-related CLI args based on options.ignoreEngines and the detected package manager, then pass them via the args field.

The logic should be roughly:
1. After detecting the package manager (line 254), compute engine args based on options.ignoreEngines and packageManager.name
2. For npm: args = ["--no-engine-strict"]
3. For pnpm: args = ["--config.engine-strict=false"]
4. For yarn: args = ["--ignore-engines"]
5. If ignoreEngines is false/undefined, args = []
6. Pass args to installDependencies: await installDependencies({ cwd: projectPath, silent: true, args })

The tests in update.test.ts already verify the expected behavior — they just don't pass because the implementation is missing.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +97 to +100
switch (severityNumber) {
case SeverityNumber.INFO:
this.originalConsole.log(...args);
break;
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.

🟡 console.info() delegated to originalConsole.log() instead of originalConsole.info()

Both log() and info() methods use SeverityNumber.INFO when calling #handleLog. In the switch at line 98, SeverityNumber.INFO always maps to this.originalConsole.log(...). This means console.info() calls are routed through the original console.log instead of the original console.info. The changeset explicitly states this fix "delegates to original console methods to preserve log chain when other interceptors (like Sentry) are present", but Sentry patches console.info separately — so info calls still bypass Sentry's console.info hook.

The switch treats log and info identically

log() at line 72 and info() at line 76 both pass SeverityNumber.INFO to #handleLog. The switch at line 98 has a single case SeverityNumber.INFO: that calls this.originalConsole.log(...), never this.originalConsole.info(...).

Prompt for agents
The root issue is that both log() and info() use SeverityNumber.INFO, so the switch statement cannot distinguish between them. To fix this properly, the #handleLog method needs an additional signal — for example, passing the original method name or using the severityText parameter (which is already "Log" vs "Info") to decide which original console method to call.

One approach: use severityText to decide:
  case SeverityNumber.INFO:
    if (severityText === "Info") {
      this.originalConsole.info(...args);
    } else {
      this.originalConsole.log(...args);
    }
    break;

This ensures console.info() calls flow through the original console.info, preserving interceptor chains from Sentry and similar tools.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +143 to +144
idleTimeoutMillis: env.DATABASE_CONNECTION_TIMEOUT * 1000,
connectionTimeoutMillis: env.DATABASE_CONNECTION_TIMEOUT * 1000,
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.

🚩 DATABASE_POOL_TIMEOUT env var is now unused after PrismaPg migration

The old Prisma connection string accepted pool_timeout (mapped from env.DATABASE_POOL_TIMEOUT, default 60s) and connection_timeout (mapped from env.DATABASE_CONNECTION_TIMEOUT, default 20s). The new PrismaPg adapter at apps/webapp/app/db.server.ts:143-144 uses env.DATABASE_CONNECTION_TIMEOUT * 1000 for both idleTimeoutMillis and connectionTimeoutMillis. The DATABASE_POOL_TIMEOUT env var defined at apps/webapp/app/env.server.ts:103 is now dead — any existing deployments that tuned DATABASE_POOL_TIMEOUT separately from DATABASE_CONNECTION_TIMEOUT will silently lose that customization. Additionally, idleTimeoutMillis (how long idle connections stay in the pool) is semantically different from the old Prisma pool_timeout (how long to wait for a free connection). The 20s idle timeout may cause more connection churn than the previous 60s pool_timeout in high-concurrency scenarios.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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