Unified · Split
| @@ -39,6 +39,48 @@ const trim = (value: string | undefined): string | undefined => { · 38 unmodified lines | ||
| 39 | 39 | return candidate && candidate.length > 0 ? candidate : undefined; |
| 40 | 40 | }; |
| 41 | 41 | |
| 42 | +const isPlanetScalePostgresUrl = (value: string): boolean => { | |
| 43 | + try { | |
| 44 | + const parsed = new URL(value); | |
| 45 | + return ( | |
| 46 | + (parsed.protocol === "postgres:" || parsed.protocol === "postgresql:") | |
| 47 | + && parsed.hostname.endsWith(".pg.psdb.cloud") | |
| 48 | + ); | |
| 49 | + } catch { | |
| 50 | + return false; | |
| 51 | + } | |
| 52 | +}; | |
| 53 | + | |
| 54 | +const deriveRuntimeDatabaseUrl = (value: string): string => { | |
| 55 | + const configuredTarget = trim(process.env.CONTROL_PLANE_POSTGRES_CONNECTION_TARGET)?.toLowerCase(); | |
| 56 | + | |
| 57 | + if (configuredTarget === "direct") { | |
| 58 | + return value; | |
| 59 | + } | |
| 60 | + | |
| 61 | + const shouldPreferPgbouncer = | |
| 62 | + configuredTarget === "pgbouncer" | |
| 63 | + || (configuredTarget === undefined && process.env.NODE_ENV === "production"); | |
| 64 | + | |
| 65 | + if (!shouldPreferPgbouncer || !isPlanetScalePostgresUrl(value)) { | |
| 66 | + return value; | |
| 67 | + } | |
| 68 | + | |
| 69 | + try { | |
| 70 | + const parsed = new URL(value); | |
| 71 | + const port = parsed.port.length > 0 ? parsed.port : "5432"; | |
| 72 | + | |
| 73 | + if (port !== "5432") { | |
| 74 | + return value; | |
| 75 | + } | |
| 76 | + | |
| 77 | + parsed.port = "6432"; | |
| 78 | + return parsed.toString(); | |
| 79 | + } catch { | |
| 80 | + return value; | |
| 81 | + } | |
| 82 | +}; | |
| 83 | + | |
| 42 | 84 | const defaultControlPlaneStateRootDir = ".executor-v2/web-state"; |
| 43 | 85 | const defaultControlPlaneDataDir = `${defaultControlPlaneStateRootDir}/control-plane-pgdata`; |
| 44 | 86 | |
| @@ -75,16 +117,17 @@ const toAccountScopedIds = (subject: string) => { · 30 unmodified lines | ||
| 75 | 117 | }; |
| 76 | 118 | |
| 77 | 119 | const resolveDatabaseUrl = (): string | undefined => { |
| 78 | − const candidates = [ | |
| 79 | − process.env.CONTROL_PLANE_DATABASE_URL, | |
| 80 | − process.env.DATABASE_URL, | |
| 81 | − process.env.POSTGRES_URL, | |
| 82 | − ]; | |
| 120 | + const override = trim(process.env.CONTROL_PLANE_DATABASE_URL); | |
| 121 | + if (override) { | |
| 122 | + return override; | |
| 123 | + } | |
| 124 | + | |
| 125 | + const candidates = [process.env.DATABASE_URL, process.env.POSTGRES_URL]; | |
| 83 | 126 | |
| 84 | 127 | for (const candidate of candidates) { |
| 85 | 128 | const value = trim(candidate); |
| 86 | 129 | if (value) { |
| 87 | − return value; | |
| 130 | + return deriveRuntimeDatabaseUrl(value); | |
| 88 | 131 | } |
| 89 | 132 | } |
| 90 | 133 | |