refactor: eliminate all catch(err: any) with proper unknown typing + type email transport
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 19m10s
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 19m10s
- Replace all catch(err: any) with catch(err: unknown) across 8 source files - Add errorMessage() and errorCode() helpers for safe error property access - Type nodemailer transport config as SMTPTransport.Options (was any) - Type health endpoint databaseStatus (was any) - Type convert route margin param (was any) - Change queryWithRetry params from any[] to unknown[] - Update isTransientError to require Error instances (was accepting plain objects) - 19 new TDD tests (error-type-safety.test.ts) - Updated existing tests to use proper Error instances - 598 tests total, all passing, zero type errors
This commit is contained in:
parent
da049b77e3
commit
5a7ee79316
12 changed files with 221 additions and 98 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import pg from "pg";
|
||||
|
||||
import logger from "./logger.js";
|
||||
import { isTransientError } from "../utils/errors.js";
|
||||
import { isTransientError, errorMessage, errorCode } from "../utils/errors.js";
|
||||
const { Pool } = pg;
|
||||
|
||||
const pool = new Pool({
|
||||
|
|
@ -35,10 +35,10 @@ export { isTransientError } from "../utils/errors.js";
|
|||
*/
|
||||
export async function queryWithRetry(
|
||||
queryText: string,
|
||||
params?: any[],
|
||||
params?: unknown[],
|
||||
maxRetries = 3
|
||||
): Promise<pg.QueryResult> {
|
||||
let lastError: any;
|
||||
let lastError: unknown;
|
||||
|
||||
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
||||
let client: pg.PoolClient | undefined;
|
||||
|
|
@ -47,7 +47,7 @@ export async function queryWithRetry(
|
|||
const result = await client.query(queryText, params);
|
||||
client.release(); // Return healthy connection to pool
|
||||
return result;
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
// Destroy the bad connection so pool doesn't reuse it
|
||||
if (client) {
|
||||
try { client.release(true); } catch (_) { /* already destroyed */ }
|
||||
|
|
@ -61,7 +61,7 @@ export async function queryWithRetry(
|
|||
|
||||
const delayMs = Math.min(1000 * Math.pow(2, attempt), 5000); // 1s, 2s, 4s (capped at 5s)
|
||||
logger.warn(
|
||||
{ err: err.message, code: err.code, attempt: attempt + 1, maxRetries, delayMs },
|
||||
{ err: errorMessage(err), code: errorCode(err), attempt: attempt + 1, maxRetries, delayMs },
|
||||
"Transient DB error, destroying bad connection and retrying..."
|
||||
);
|
||||
await new Promise(resolve => setTimeout(resolve, delayMs));
|
||||
|
|
@ -77,7 +77,7 @@ export async function queryWithRetry(
|
|||
* fresh connections to the new PgBouncer pod.
|
||||
*/
|
||||
export async function connectWithRetry(maxRetries = 3): Promise<pg.PoolClient> {
|
||||
let lastError: any;
|
||||
let lastError: unknown;
|
||||
|
||||
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
|
|
@ -85,7 +85,7 @@ export async function connectWithRetry(maxRetries = 3): Promise<pg.PoolClient> {
|
|||
// Validate the connection is actually alive
|
||||
try {
|
||||
await client.query("SELECT 1");
|
||||
} catch (validationErr: any) {
|
||||
} catch (validationErr: unknown) {
|
||||
// Connection is dead — destroy it and retry
|
||||
try { client.release(true); } catch (_) {}
|
||||
if (!isTransientError(validationErr) || attempt === maxRetries) {
|
||||
|
|
@ -93,14 +93,14 @@ export async function connectWithRetry(maxRetries = 3): Promise<pg.PoolClient> {
|
|||
}
|
||||
const delayMs = Math.min(1000 * Math.pow(2, attempt), 5000);
|
||||
logger.warn(
|
||||
{ err: validationErr.message, code: validationErr.code, attempt: attempt + 1 },
|
||||
{ err: errorMessage(validationErr), code: errorCode(validationErr), attempt: attempt + 1 },
|
||||
"Connection validation failed, destroying and retrying..."
|
||||
);
|
||||
await new Promise(resolve => setTimeout(resolve, delayMs));
|
||||
continue;
|
||||
}
|
||||
return client;
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
lastError = err;
|
||||
|
||||
if (!isTransientError(err) || attempt === maxRetries) {
|
||||
|
|
@ -109,7 +109,7 @@ export async function connectWithRetry(maxRetries = 3): Promise<pg.PoolClient> {
|
|||
|
||||
const delayMs = Math.min(1000 * Math.pow(2, attempt), 5000);
|
||||
logger.warn(
|
||||
{ err: err.message, code: err.code, attempt: attempt + 1, maxRetries, delayMs },
|
||||
{ err: errorMessage(err), code: errorCode(err), attempt: attempt + 1, maxRetries, delayMs },
|
||||
"Transient DB connect error, retrying..."
|
||||
);
|
||||
await new Promise(resolve => setTimeout(resolve, delayMs));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue