134 lines
6.0 KiB
TypeScript
134 lines
6.0 KiB
TypeScript
import { EventEmitter } from 'events';
|
|
import { PgListenClient, PgPool, PgPoolConfig } from './pg-types';
|
|
/**
|
|
* A node-postgres pool config / connection string, optionally carrying the
|
|
* BullMQ-specific `schema` (the connection-level namespace for all queues) and
|
|
* `skipVersionCheck` (bypass the minimum-server-version assertion).
|
|
*/
|
|
export type PostgresPoolConfig = PgPoolConfig & {
|
|
schema?: string;
|
|
skipVersionCheck?: boolean;
|
|
};
|
|
/**
|
|
* What the user may pass as the PostgreSQL `connection` option:
|
|
*
|
|
* - an already-constructed `pg.Pool` instance (we use it as-is and do NOT close
|
|
* it on `close()` — the caller owns its lifecycle), or
|
|
* - a node-postgres pool config / connection string (we lazily `require('pg')`
|
|
* and construct the pool ourselves, owning its lifecycle).
|
|
*
|
|
* The optional `schema` (the namespace for all queues) is only read from the
|
|
* **config-object** form, because that is the only case where we build the pool
|
|
* ourselves and can pin each connection's `search_path` to it. A bare
|
|
* connection string or an already-constructed `pg.Pool` always uses
|
|
* {@link DEFAULT_SCHEMA} — a raw pool cannot carry a `schema`, and we cannot set
|
|
* the `search_path` on a pool we did not create. To select a different schema,
|
|
* pass a config object (a connection string can be wrapped as
|
|
* `{ connectionString, schema }`; a pre-built pool must be configured with the
|
|
* desired `search_path` by the caller).
|
|
*/
|
|
export type PostgresConnectionOptions = PgPool | PostgresPoolConfig | string;
|
|
/**
|
|
* Owns the PostgreSQL connection resources for a single backend:
|
|
*
|
|
* - a `pg.Pool` for regular, short-lived queries, and
|
|
* - a dedicated, long-lived `LISTEN` client used by the blocking
|
|
* "wait for job" primitive (lazily established).
|
|
*
|
|
* Lifecycle mirrors {@link RedisConnection}: it is an {@link EventEmitter} that
|
|
* surfaces normalized `'ready' | 'error' | 'close'` events, exposes
|
|
* {@link PostgresConnection.waitUntilReady} (which also runs the schema
|
|
* migrations exactly once, on a dedicated checked-out client) and
|
|
* {@link PostgresConnection.close}.
|
|
*/
|
|
export declare class PostgresConnection extends EventEmitter {
|
|
readonly pool: PgPool;
|
|
/**
|
|
* The PostgreSQL schema (namespace) this connection's queues live in. It is
|
|
* applied to every pooled connection's `search_path`, so the `.sql` command
|
|
* files (and the operation functions) reference unqualified names and stay
|
|
* portable — the schema selects the namespace, never the SQL itself.
|
|
*/
|
|
readonly schema: string;
|
|
/**
|
|
* `true` when this instance constructed the pool (and must therefore close
|
|
* it). `false` when the user passed in their own `pg.Pool`.
|
|
*/
|
|
private readonly ownsPool;
|
|
/**
|
|
* When `true`, the minimum-server-version assertion in {@link runMigrations}
|
|
* is skipped. Only settable via a config object (a raw `pg.Pool` or a bare
|
|
* connection string always run the check).
|
|
*/
|
|
private readonly skipVersionCheck;
|
|
private readyPromise;
|
|
private closing;
|
|
private listenClient;
|
|
/**
|
|
* Memoizes the in-flight {@link PostgresConnection.getListenClient}
|
|
* establishment so concurrent first-callers (e.g. a backend naming its
|
|
* connection in `waitUntilReady` while its consume loop also asks for the
|
|
* LISTEN client) all share one connection instead of each opening a
|
|
* duplicate.
|
|
*/
|
|
private listenClientPromise;
|
|
/**
|
|
* When this instance owns the pool, the lazily-required `pg` module and the
|
|
* resolved client config (with the pinned `search_path`) used to build a
|
|
* *dedicated standalone* `LISTEN` connection — so a long-lived `LISTEN` never
|
|
* consumes a pool slot. Undefined when the user passed their own `pg.Pool`
|
|
* (then the `LISTEN` client is checked out of that pool instead).
|
|
*/
|
|
private readonly pgModule;
|
|
private readonly listenClientConfig;
|
|
/**
|
|
* `true` when {@link listenClient} is a standalone `pg.Client` we must `end()`
|
|
* (owned pool); `false` when it is a pooled client we must `release()`.
|
|
*/
|
|
private listenClientIsStandalone;
|
|
constructor(connection: PostgresConnectionOptions);
|
|
/**
|
|
* Forwards an underlying pool / LISTEN-client error as this connection's
|
|
* `'error'` event, but only when a listener is attached. `EventEmitter.emit`
|
|
* throws when emitting `'error'` with no listeners, so an unguarded forward
|
|
* would turn an idle-client error into a hard process crash. Mirrors the
|
|
* guard in {@link RedisConnection}.
|
|
*/
|
|
private emitError;
|
|
/**
|
|
* Resolves once the pool is reachable and the schema is up to date.
|
|
*
|
|
* Idempotent and memoized: the migration runs exactly once per connection,
|
|
* on a single dedicated client checked out of the pool (so the migration's
|
|
* advisory lock and transaction share one session — see {@link runMigrations}).
|
|
*/
|
|
waitUntilReady(): Promise<void>;
|
|
private bootstrap;
|
|
/**
|
|
* Returns the dedicated client used for `LISTEN`/`NOTIFY`, establishing it on
|
|
* first use.
|
|
*
|
|
* When this connection owns the pool we use a *standalone* `pg.Client` (its
|
|
* own dedicated TCP connection) so the long-lived `LISTEN` never consumes a
|
|
* pool slot — this is what lets the query pool run at `max: 1` without
|
|
* deadlocking. When the user supplied their own `pg.Pool` we check a client
|
|
* out of it (so such pools should be sized `>= 2`).
|
|
*/
|
|
getListenClient(): Promise<PgListenClient>;
|
|
/**
|
|
* Truthy once {@link PostgresConnection.close} has begun.
|
|
*/
|
|
get isClosing(): Promise<void> | undefined;
|
|
/**
|
|
* Closes the connection: releases the `LISTEN` client and (if owned) ends the
|
|
* pool. Safe to call multiple times.
|
|
*/
|
|
close(): Promise<void>;
|
|
/**
|
|
* Forcibly tears down the connection. For PostgreSQL there is no distinct
|
|
* "disconnect without waiting" semantics beyond closing, so this delegates to
|
|
* {@link PostgresConnection.close}.
|
|
*/
|
|
disconnect(): Promise<void>;
|
|
}
|