@spfn/core 0.2.0-beta.43 → 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/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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spfn/core",
3
- "version": "0.2.0-beta.43",
3
+ "version": "0.2.0-beta.45",
4
4
  "description": "SPFN Framework Core - File-based routing, transactions, repository pattern",
5
5
  "type": "module",
6
6
  "exports": {