diff --git a/internal/db/runtime-store.ts b/internal/db/runtime-store.ts index 9647b60f..849d20fe 100644 --- a/internal/db/runtime-store.ts +++ b/internal/db/runtime-store.ts @@ -1816,6 +1816,35 @@ export class PostgresCloudRuntimeStore { }); } + resetPostgresPoolAfterTransientFailure(classified, retry = {}) { + if (classified?.connection?.queryResult !== "connect_timeout") return false; + const pool = this.pool; + if (!pool) return false; + this.pool = null; + this.logger?.warn?.({ + event: "postgres_runtime_pool_reset_after_transient_failure", + blocker: classified.blocker, + queryResult: classified.connection?.queryResult ?? "query_blocked", + errorCode: classified.connection?.errorCode ?? "UNKNOWN", + retryAttempt: Number.isFinite(Number(retry.attempt)) ? Number(retry.attempt) : null, + retryMaxAttempts: Number.isFinite(Number(retry.maxAttempts)) ? Number(retry.maxAttempts) : null, + retrying: retry.retrying === true, + valuesRedacted: true, + endpointRedacted: true + }); + if (typeof pool.end === "function") { + Promise.resolve() + .then(() => pool.end()) + .catch((error) => this.logger?.warn?.({ + event: "postgres_runtime_pool_reset_failed", + errorCode: error?.code ?? "UNKNOWN", + valuesRedacted: true, + endpointRedacted: true + })); + } + return true; + } + async query(sql, params = []) { const retry = this.runtimeQueryRetryPolicy(); for (let attempt = 1; attempt <= retry.maxAttempts; attempt += 1) { @@ -1833,6 +1862,13 @@ export class PostgresCloudRuntimeStore { delayMs, label: `${attempt}/${retry.maxAttempts}` }); + this.resetPostgresPoolAfterTransientFailure(classified, { + attempt, + maxAttempts: retry.maxAttempts, + retrying, + delayMs, + label: `${attempt}/${retry.maxAttempts}` + }); if (!retrying) throw error; await delayRuntimeDbQueryRetry(delayMs); }