v134 · javascript

Connection pool

A connection pool hands out limited resources and reclaims them on scope exit. With using, the checkout returns a Disposable: Symbol.dispose automatically returns the connection when the block exits — even if an exception is thrown.

Feature detection: checking…
Without using — manual release required
function runQuery(query) { const conn = pool.checkout(); // must remember to release try { return conn.query(query); } finally { pool.release(conn); // easy to forget } } // If the dev forgets the try/finally: function badQuery(query) { const conn = pool.checkout(); return conn.query(query); // leaks on throw! }
With using — automatic on scope exit
function runQuery(query) { using conn = pool.checkout(); // conn[Symbol.dispose]() called // when block exits — throw or not return conn.query(query); } // Works even if query throws: function riskyQuery(query) { using conn = pool.checkout(); if (Math.random() < 0.4) { throw new Error('simulated failure'); } return conn.query(query); // conn is always released }
Connection pool — 6 slots idle
checked out: 0
available: 6
queries run: 0
leaks prevented: 0

Activity log:

Run a query to see checkout/release lifecycle.
// Disposable connection — Symbol.dispose auto-releases to pool
class PooledConnection {
  constructor(id, pool, log) {
    this.id = id;
    this._pool = pool;
    this._log = log;
  }

  query(sql) {
    this._log(`conn#${this.id} executing: ${sql}`);
    return { rows: [], conn: this.id };
  }

  // Called by `using` on scope exit
  [Symbol.dispose]() {
    this._pool.release(this);
    this._log(`conn#${this.id} auto-released to pool`);
  }
}

// Pool.checkout returns a PooledConnection
// `using conn = pool.checkout()` guarantees release
function processRequest(sql) {
  using conn = pool.checkout();
  return conn.query(sql); // conn released here, always
}

see also

references