Retry & Pooling

Ride out transient network failures, and see what the connection pool is doing.
Both are configured on DBConfig and read back from the ORM.

Retry Configuration

db.ts
import { Stabilize, DBType } from "stabilize-orm";
const orm = new Stabilize({
type: DBType.Postgres,
connectionString: process.env.DATABASE_URL!,
retryAttempts: 3, // default 3
retryDelay: 1000, // default 1000ms
maxJitter: 100, // default 100ms
});

Which Statements Retry

Reads retry. Writes do not.

Retry applies only to statements that begin with SELECT, PRAGMA, SHOW, EXPLAIN or VALUES (leading comments and whitespace are stripped first). Every write runs exactly once, always. This is deliberate: a write that failed after committing on the server, but before the response arrived, would be applied twice by a retry. Reads have no such hazard.

behaviour.ts
// Retried on failure, up to retryAttempts
await repo.find().where("status = ?", "active").execute(db.client);
await db.rawQuery("SELECT * FROM users");
await db.rawQuery("PRAGMA table_info(users)");
// Never retried - one attempt only
await repo.create({ title: "Draft" });
await db.rawExec("UPDATE users SET active = ? WHERE id = ?", [true, 1]);
// To effectively disable retry, set it to 1
const noRetry = new Stabilize({
type: DBType.Postgres,
connectionString: url,
retryAttempts: 1,
});

Backoff

Delays double with each attempt, plus a random jitter so that many clients failing together do not all retry in lockstep:

backoff.ts
delay = retryDelay * 2^(attempt - 1) + random(0 .. maxJitter)
// With retryDelay: 1000, maxJitter: 100
// attempt 1 -> ~1000ms + 0-100ms
// attempt 2 -> ~2000ms + 0-100ms
// attempt 3 -> ~4000ms + 0-100ms

The multiplier is fixed at 2 and there is no option to change it — there is no initialDelay, maxDelay or per-error-code list. maxJitter is the only knob on the curve. Set maxJitter: 0 in tests to make timing deterministic.

Health Checks

The ORM and a repository each expose their own healthCheck(), with different return shapes. The ORM one probes the connection and cache; the repository one counts rows in its table.

health.ts
const health = await orm.healthCheck();
// {
// status: "healthy" | "unhealthy",
// database: "sqlite" | "postgres" | "mysql" | "mssql" | "mongodb",
// latencyMs: 0.42,
// cacheStatus: "disabled" | "in-memory" | "connected" | "connected (miss)" | "unknown"
// }
const userHealth = await userRepo.healthCheck();
// {
// status: "healthy" | "unhealthy",
// table: "users",
// rows: 128, // -1 if the count failed
// latencyMs: 0.31
// }
route.ts
app.get("/healthz", async (req, res) => {
const health = await orm.healthCheck();
res.status(health.status === "healthy" ? 200 : 503).json(health);
});

Pool Statistics

orm.poolStats() reports { active, idle, total }. Only SQL Server returns real numbers. Every other dialect returns -1 in all three fields:

pool.ts
const { active, idle, total } = await orm.poolStats();
// SQL Server : { active: borrowed, idle: available, total: size }
// PostgreSQL : { active: -1, idle: -1, total: -1 }
// MySQL : { active: -1, idle: -1, total: -1 }
// SQLite : { active: -1, idle: -1, total: -1 } <- no pool at all

The non-MSSQL branches never fire

This is narrower than it looks, and worth knowing before you build a dashboard on it. poolStats() inspects its own DBClient wrapper rather than the driver object underneath, then checks a driver-pool shape — totalCount, then _allConnections, then size — against it. Only the SQL Server pool presents size, and that last branch is additionally gated on the dialect being DBType.MSSQL. Postgres exposes totalCount on the pool, but not on the wrapper, so the check misses it. Hence the sentinels.

Pool size is not configurable here

Every pool is constructed from connectionString alone. There is no max, min, idleTimeout or connectionLimit field on DBConfig. To size a pool, put it in the connection string — e.g. ?connection_limit=20 for PostgreSQL or ?connectionLimit=20 for MySQL. Treat -1 as "not available", not as a problem: a check that asserts total > 0 fails on everything except SQL Server.