A client that stalls mid-pipeline (Parse sent, no Sync) while keeping its socket open would hold the query queue's handler affinity forever and starve every other connection: affinity only releases on detach, and detach needs close/error/idle-timeout. The dev-db previously disabled the idle timeout (pglite-socket defaults to 0). Unreachable for postgres.js in practice (a crashed client closes its socket), but a 30s idle timeout (env-overridable via DEV_DB_IDLE_TIMEOUT_MS) makes the starvation impossible instead of merely unlikely. The timer resets on every data event, so only a dead client trips it.
Unified · Split
| @@ -111,6 +111,12 @@ const server = new PGLiteSocketServer({ · 110 unmodified lines | |||
| 111 | port: PORT, | 111 | port: PORT, |
| 112 | host: "127.0.0.1", | 112 | host: "127.0.0.1", |
| 113 | maxConnections: Number(process.env.DEV_DB_MAX_CONNECTIONS ?? 1000), | 113 | maxConnections: Number(process.env.DEV_DB_MAX_CONNECTIONS ?? 1000), |
| 114 | // Backstop for pipeline affinity: a client that stalls mid-pipeline (Parse | ||
| 115 | // sent, no Sync) with its socket still OPEN would hold the queue's handler | ||
| 116 | // affinity forever and starve every other connection, since affinity only | ||
| 117 | // releases on detach and detach needs close/error/idle-timeout. In ms; the | ||
| 118 | // timer resets on every data event, so only a genuinely dead client trips it. | ||
| 119 | idleTimeout: Number(process.env.DEV_DB_IDLE_TIMEOUT_MS ?? 30_000), | ||
| 114 | }); | 120 | }); |
| 115 | 121 | ||
| 116 | await server.start(); | 122 | await server.start(); |