@spfn/core 0.2.0-beta.44 → 0.2.0-beta.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/db/index.d.ts +85 -1
- package/dist/db/index.js +178 -11
- package/dist/db/index.js.map +1 -1
- package/docs/database.md +66 -0
- package/package.json +1 -1
package/docs/database.md
CHANGED
|
@@ -311,6 +311,72 @@ const isHealthy = await checkConnection(getDatabase('write'));
|
|
|
311
311
|
|
|
312
312
|
---
|
|
313
313
|
|
|
314
|
+
## Pool Recovery
|
|
315
|
+
|
|
316
|
+
`@spfn/core` rebuilds the entire `postgres.js` pool (atomic swap) in two situations:
|
|
317
|
+
|
|
318
|
+
1. **Periodic health check** — every `DB_HEALTH_CHECK_INTERVAL` (default 60s),
|
|
319
|
+
`SELECT 1` runs on write/read. On failure the pool is destroyed and recreated.
|
|
320
|
+
2. **Query-error fast-path** — real query errors caught by `BaseRepository.withContext`
|
|
321
|
+
and `@Transactional` middleware are classified; once `DB_RECONNECT_ERROR_THRESHOLD`
|
|
322
|
+
(default 3) connection-level failures occur within `DB_RECONNECT_ERROR_WINDOW_MS`
|
|
323
|
+
(default 10s), a rebuild fires without waiting for the periodic tick.
|
|
324
|
+
|
|
325
|
+
Both paths share the same atomic-swap implementation: the new pool is created and
|
|
326
|
+
validated *before* the global reference is replaced, and the old pool is torn down
|
|
327
|
+
only after the swap completes. Concurrent triggers coalesce to a single rebuild.
|
|
328
|
+
|
|
329
|
+
### Manual trigger
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
import { forceReconnectDatabase } from '@spfn/core/db';
|
|
333
|
+
|
|
334
|
+
// Admin endpoint
|
|
335
|
+
route.post('/admin/db/reconnect')
|
|
336
|
+
.handler(async (c) => {
|
|
337
|
+
const ran = await forceReconnectDatabase('admin_request');
|
|
338
|
+
return c.json({ reconnected: ran });
|
|
339
|
+
});
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Returns `false` if the database is not initialized, is currently closing, or a
|
|
343
|
+
reconnect is already in progress.
|
|
344
|
+
|
|
345
|
+
### Environment variables
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
# Periodic health check
|
|
349
|
+
DB_HEALTH_CHECK_INTERVAL=60000 # ms between SELECT 1 probes
|
|
350
|
+
DB_HEALTH_CHECK_MAX_RETRIES=3 # retries per rebuild attempt
|
|
351
|
+
DB_HEALTH_CHECK_RETRY_INTERVAL=5000 # delay between retries
|
|
352
|
+
|
|
353
|
+
# Query-error fast-path
|
|
354
|
+
DB_RECONNECT_ERROR_THRESHOLD=3 # errors needed to trigger rebuild
|
|
355
|
+
DB_RECONNECT_ERROR_WINDOW_MS=10000 # sliding window length (min 1000ms)
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Advanced: custom catch sites
|
|
359
|
+
|
|
360
|
+
Application code that executes drizzle queries outside `BaseRepository` and
|
|
361
|
+
`@Transactional` can feed the fast-path manually:
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
import { reportDatabaseError } from '@spfn/core/db';
|
|
365
|
+
|
|
366
|
+
try {
|
|
367
|
+
await db.execute(sql`...`);
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
reportDatabaseError(error); // no-op for non-connection errors
|
|
371
|
+
throw error;
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Inside `BaseRepository` / `@Transactional` this is already automatic — no
|
|
376
|
+
manual call needed.
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
314
380
|
## Cleanup
|
|
315
381
|
|
|
316
382
|
```typescript
|