The libsql backend ran every operation on one shared connection. On a remote database that connection is a Hrana stream, and each response carries the baton for the stream's next request. An operation dropped while its request was in flight (a client that disconnected, the auth timeout) never received the new baton, so the connection kept the spent one and the server refused every later request with "Received a baton that has already been used". From then on every login and every authenticated request failed with a 500 until pnpr restarted. One shared stream also put concurrent operations into each other's transactions. Operations now check a connection out of a pool and run alone on it. A connection returns to the pool only after its operation succeeded outside a transaction; any other is closed and replaced on a later checkout. This is what sqlx does for the PostgreSQL and MySQL backends. Pooled connections keep their HTTP client, so reuse costs no new TCP or TLS handshake, which a connection per operation would have paid on every token lookup. backend.libsql.maxConnections sizes the pool, defaulting to 10 like sqlx.
384 B
384 B
@pnpm/pnpr
| @pnpm/pnpr |
|---|
| patch |
pnpr no longer loses its libsql or Turso auth database after a request is cut off. Before, a client that disconnected during a token lookup could make every later login and authenticated request fail with a 500 until pnpr restarted. The new backend.libsql.maxConnections setting limits how many auth database operations run at once, and defaults to 10.