@rotorsoft/act-pg 1.9.3 → 1.10.1
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/README.md +24 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/postgres-store.d.ts +26 -6
- package/dist/@types/postgres-store.d.ts.map +1 -1
- package/dist/index.cjs +93 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +93 -16
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -110,18 +110,18 @@ type Config = Readonly<{
|
|
|
110
110
|
*
|
|
111
111
|
* @example Connection pooling configuration
|
|
112
112
|
* ```typescript
|
|
113
|
-
* // PostgresStore uses node-postgres (pg) connection pooling
|
|
114
|
-
* //
|
|
115
|
-
* //
|
|
116
|
-
* //
|
|
117
|
-
* // PGMAXCONNECTIONS, PGIDLETIMEOUT, etc.
|
|
113
|
+
* // PostgresStore uses node-postgres (pg) connection pooling with
|
|
114
|
+
* // opinionated defaults: max 20, connectionTimeoutMillis 10s,
|
|
115
|
+
* // idleTimeoutMillis 30s, statement_timeout 60s. Any pg.PoolConfig
|
|
116
|
+
* // field passed to the constructor overrides the default.
|
|
118
117
|
*
|
|
119
118
|
* const pgStore = new PostgresStore({
|
|
120
119
|
* host: "db.example.com",
|
|
121
120
|
* port: 5432,
|
|
122
121
|
* database: "production",
|
|
123
122
|
* user: "app_user",
|
|
124
|
-
* password: process.env.DB_PASSWORD
|
|
123
|
+
* password: process.env.DB_PASSWORD,
|
|
124
|
+
* max: 40 // lanes × streamLimit + API concurrency + headroom
|
|
125
125
|
* });
|
|
126
126
|
* ```
|
|
127
127
|
*
|
|
@@ -212,6 +212,15 @@ export declare class PostgresStore implements Store {
|
|
|
212
212
|
* @param config Partial configuration (host, port, user, password, schema, table, etc.)
|
|
213
213
|
*/
|
|
214
214
|
constructor(config?: Partial<Config>);
|
|
215
|
+
/**
|
|
216
|
+
* Acquire a pooled client, translating acquisition failures into
|
|
217
|
+
* {@link StoreError} with the calling operation as context. With the
|
|
218
|
+
* default `connectionTimeoutMillis`, a saturated pool fails here
|
|
219
|
+
* after 10s with `Store operation "<operation>" failed` (driver
|
|
220
|
+
* error preserved as `cause`) instead of hanging indefinitely.
|
|
221
|
+
* Every method that checks out a client routes through this helper.
|
|
222
|
+
*/
|
|
223
|
+
private _client;
|
|
215
224
|
/**
|
|
216
225
|
* Dispose of the store and close all database connections.
|
|
217
226
|
* Releases any active LISTEN client first so the pool can drain cleanly.
|
|
@@ -303,6 +312,17 @@ export declare class PostgresStore implements Store {
|
|
|
303
312
|
* @returns Blocked leases.
|
|
304
313
|
*/
|
|
305
314
|
block(leases: BlockedLease[]): Promise<BlockedLease[]>;
|
|
315
|
+
/**
|
|
316
|
+
* Hold the matched streams out of {@link claim} until `deferred_at`
|
|
317
|
+
* (ms since epoch) — see {@link Store.defer}. Persists `deferred_at`
|
|
318
|
+
* (as a `timestamptz`) so the skip is honored by every competing
|
|
319
|
+
* worker; `claim` filters on `deferred_at <= NOW()`. Accepts an
|
|
320
|
+
* explicit list of names or a {@link StreamFilter}, mirroring
|
|
321
|
+
* {@link reset}/{@link prioritize}. Cleared by ack/block/reset/unblock.
|
|
322
|
+
*
|
|
323
|
+
* @returns Count of streams whose `deferred_at` was set.
|
|
324
|
+
*/
|
|
325
|
+
defer(input: string[] | StreamFilter, deferred_at: number): Promise<number>;
|
|
306
326
|
/**
|
|
307
327
|
* Reset watermarks for the given streams to -1, clearing retry, blocked,
|
|
308
328
|
* error, and lease state so they can be replayed from the beginning.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-store.d.ts","sourceRoot":"","sources":["../../src/postgres-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACT,SAAS,EACT,KAAK,EAEL,OAAO,EACP,cAAc,EACd,KAAK,EACL,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,MAAM,EACN,OAAO,EACP,KAAK,EACL,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAQxB,OAAO,EAEL,KAAK,UAAU,EAGhB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;AAUpB,KAAK,MAAM,GAAG,QAAQ,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,cAAc,CAAC,EAAE,UAAU,CAAC;CAC7B,CAAC,GACA,EAAE,CAAC,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"postgres-store.d.ts","sourceRoot":"","sources":["../../src/postgres-store.ts"],"names":[],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -74,7 +74,35 @@ var DEFAULT_CONFIG = {
|
|
|
74
74
|
password: "postgres",
|
|
75
75
|
schema: "public",
|
|
76
76
|
table: "events",
|
|
77
|
-
notify: false
|
|
77
|
+
notify: false,
|
|
78
|
+
// Opinionated pool defaults (#1119). node-postgres ships `max: 10`
|
|
79
|
+
// with no acquisition timeout and no statement timeout — a saturated
|
|
80
|
+
// pool makes every caller hang indefinitely instead of failing with
|
|
81
|
+
// a diagnosable error. Nearly every store method holds a client for
|
|
82
|
+
// a multi-statement transaction, so multi-lane drains plus API
|
|
83
|
+
// traffic can exhaust a 10-client pool quickly. All four values are
|
|
84
|
+
// plain `pg.PoolConfig` fields — caller config overrides any of them
|
|
85
|
+
// via the constructor spread.
|
|
86
|
+
//
|
|
87
|
+
// - `max: 20` — floor for the default lane's parallel handler budget
|
|
88
|
+
// (streamLimit 10, each commit holds a client) plus API commits,
|
|
89
|
+
// the optional LISTEN client, and headroom. Sizing rule in the
|
|
90
|
+
// README: Σ per-lane streamLimit + API concurrency + notify + 2–4.
|
|
91
|
+
// - `connectionTimeoutMillis: 10_000` — fail acquisition fast (the
|
|
92
|
+
// pg default of 0 waits forever); surfaces as StoreError via
|
|
93
|
+
// `_client()` so operators see *which* operation starved.
|
|
94
|
+
// - `idleTimeoutMillis: 30_000` — keep idle clients warm across
|
|
95
|
+
// drain cycles (cycleMs can exceed the pg default of 10s in
|
|
96
|
+
// low-traffic deployments) without pinning connections for long.
|
|
97
|
+
// - `statement_timeout: 60_000` — per-statement (not per-transaction)
|
|
98
|
+
// ceiling; every statement the store issues (claim CTE, seed DDL,
|
|
99
|
+
// truncate, restore's per-event inserts) legitimately completes
|
|
100
|
+
// orders of magnitude faster, so 60s only fires on a wedged server
|
|
101
|
+
// or a lost lock instead of holding the client hostage.
|
|
102
|
+
max: 20,
|
|
103
|
+
connectionTimeoutMillis: 1e4,
|
|
104
|
+
idleTimeoutMillis: 3e4,
|
|
105
|
+
statement_timeout: 6e4
|
|
78
106
|
};
|
|
79
107
|
var PostgresStore = class {
|
|
80
108
|
_pool;
|
|
@@ -145,6 +173,21 @@ var PostgresStore = class {
|
|
|
145
173
|
}
|
|
146
174
|
this._resolve_pii_key = this.config.pii_encryption ? (0, import_act_crypto.makeKeyResolver)(this.config.pii_encryption) : void 0;
|
|
147
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Acquire a pooled client, translating acquisition failures into
|
|
178
|
+
* {@link StoreError} with the calling operation as context. With the
|
|
179
|
+
* default `connectionTimeoutMillis`, a saturated pool fails here
|
|
180
|
+
* after 10s with `Store operation "<operation>" failed` (driver
|
|
181
|
+
* error preserved as `cause`) instead of hanging indefinitely.
|
|
182
|
+
* Every method that checks out a client routes through this helper.
|
|
183
|
+
*/
|
|
184
|
+
async _client(operation) {
|
|
185
|
+
try {
|
|
186
|
+
return await this._pool.connect();
|
|
187
|
+
} catch (error) {
|
|
188
|
+
throw new import_act.StoreError(operation, { cause: error });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
148
191
|
/**
|
|
149
192
|
* Dispose of the store and close all database connections.
|
|
150
193
|
* Releases any active LISTEN client first so the pool can drain cleanly.
|
|
@@ -178,7 +221,7 @@ var PostgresStore = class {
|
|
|
178
221
|
* @throws Error if seeding fails
|
|
179
222
|
*/
|
|
180
223
|
async seed() {
|
|
181
|
-
const client = await this.
|
|
224
|
+
const client = await this._client("seed");
|
|
182
225
|
try {
|
|
183
226
|
await client.query("BEGIN");
|
|
184
227
|
await client.query(
|
|
@@ -231,7 +274,8 @@ var PostgresStore = class {
|
|
|
231
274
|
leased_by text,
|
|
232
275
|
leased_until timestamptz,
|
|
233
276
|
priority int NOT NULL DEFAULT 0,
|
|
234
|
-
lane text NOT NULL DEFAULT 'default'
|
|
277
|
+
lane text NOT NULL DEFAULT 'default',
|
|
278
|
+
deferred_at timestamptz
|
|
235
279
|
) TABLESPACE pg_default;`
|
|
236
280
|
);
|
|
237
281
|
await client.query(
|
|
@@ -242,6 +286,10 @@ var PostgresStore = class {
|
|
|
242
286
|
`ALTER TABLE ${this._fqs}
|
|
243
287
|
ADD COLUMN IF NOT EXISTS lane text NOT NULL DEFAULT 'default';`
|
|
244
288
|
);
|
|
289
|
+
await client.query(
|
|
290
|
+
`ALTER TABLE ${this._fqs}
|
|
291
|
+
ADD COLUMN IF NOT EXISTS deferred_at timestamptz;`
|
|
292
|
+
);
|
|
245
293
|
await client.query(
|
|
246
294
|
`DROP INDEX IF EXISTS "${this.config.schema}"."${this.config.table}_streams_fetch_ix"`
|
|
247
295
|
);
|
|
@@ -386,7 +434,7 @@ var PostgresStore = class {
|
|
|
386
434
|
*/
|
|
387
435
|
async commit(stream, msgs, meta, expectedVersion) {
|
|
388
436
|
if (msgs.length === 0) return [];
|
|
389
|
-
const client = await this.
|
|
437
|
+
const client = await this._client("commit");
|
|
390
438
|
let version = -1;
|
|
391
439
|
try {
|
|
392
440
|
await client.query("BEGIN");
|
|
@@ -468,7 +516,7 @@ var PostgresStore = class {
|
|
|
468
516
|
* @returns Leased streams with metadata
|
|
469
517
|
*/
|
|
470
518
|
async claim(lagging, leading, by, millis, lane) {
|
|
471
|
-
const client = await this.
|
|
519
|
+
const client = await this._client("claim");
|
|
472
520
|
try {
|
|
473
521
|
await client.query("BEGIN");
|
|
474
522
|
const lane_clause = lane !== void 0 ? `AND s.lane = $5` : "";
|
|
@@ -482,6 +530,7 @@ var PostgresStore = class {
|
|
|
482
530
|
WHERE blocked = false
|
|
483
531
|
${lane_clause}
|
|
484
532
|
AND (leased_by IS NULL OR leased_until <= NOW())
|
|
533
|
+
AND (deferred_at IS NULL OR deferred_at <= NOW())
|
|
485
534
|
AND (s.at < 0 OR EXISTS (
|
|
486
535
|
SELECT 1 FROM ${this._fqt} e
|
|
487
536
|
WHERE e.id > s.at
|
|
@@ -549,7 +598,7 @@ var PostgresStore = class {
|
|
|
549
598
|
* @returns subscribed count and current max watermark.
|
|
550
599
|
*/
|
|
551
600
|
async subscribe(streams) {
|
|
552
|
-
const client = await this.
|
|
601
|
+
const client = await this._client("subscribe");
|
|
553
602
|
try {
|
|
554
603
|
await client.query("BEGIN");
|
|
555
604
|
let subscribed = 0;
|
|
@@ -609,7 +658,7 @@ var PostgresStore = class {
|
|
|
609
658
|
* @returns Acked leases.
|
|
610
659
|
*/
|
|
611
660
|
async ack(leases) {
|
|
612
|
-
const client = await this.
|
|
661
|
+
const client = await this._client("ack");
|
|
613
662
|
try {
|
|
614
663
|
await client.query("BEGIN");
|
|
615
664
|
const { rows } = await client.query(
|
|
@@ -623,7 +672,8 @@ var PostgresStore = class {
|
|
|
623
672
|
at = i.at,
|
|
624
673
|
retry = -1,
|
|
625
674
|
leased_by = NULL,
|
|
626
|
-
leased_until = NULL
|
|
675
|
+
leased_until = NULL,
|
|
676
|
+
deferred_at = NULL
|
|
627
677
|
FROM input i
|
|
628
678
|
WHERE s.stream = i.stream AND s.leased_by = i.by
|
|
629
679
|
RETURNING s.stream, s.source, s.at, i.by, s.retry, i.lagging, s.lane
|
|
@@ -654,7 +704,7 @@ var PostgresStore = class {
|
|
|
654
704
|
* @returns Blocked leases.
|
|
655
705
|
*/
|
|
656
706
|
async block(leases) {
|
|
657
|
-
const client = await this.
|
|
707
|
+
const client = await this._client("block");
|
|
658
708
|
try {
|
|
659
709
|
await client.query("BEGIN");
|
|
660
710
|
const { rows } = await client.query(
|
|
@@ -664,7 +714,7 @@ var PostgresStore = class {
|
|
|
664
714
|
AS x(stream text, by text, error text, lagging boolean)
|
|
665
715
|
)
|
|
666
716
|
UPDATE ${this._fqs} AS s
|
|
667
|
-
SET blocked = true, error = i.error
|
|
717
|
+
SET blocked = true, error = i.error, deferred_at = NULL
|
|
668
718
|
FROM input i
|
|
669
719
|
WHERE s.stream = i.stream AND s.leased_by = i.by AND s.blocked = false
|
|
670
720
|
RETURNING s.stream, s.source, s.at, i.by, s.retry, s.error, i.lagging, s.lane
|
|
@@ -690,6 +740,33 @@ var PostgresStore = class {
|
|
|
690
740
|
client.release();
|
|
691
741
|
}
|
|
692
742
|
}
|
|
743
|
+
/**
|
|
744
|
+
* Hold the matched streams out of {@link claim} until `deferred_at`
|
|
745
|
+
* (ms since epoch) — see {@link Store.defer}. Persists `deferred_at`
|
|
746
|
+
* (as a `timestamptz`) so the skip is honored by every competing
|
|
747
|
+
* worker; `claim` filters on `deferred_at <= NOW()`. Accepts an
|
|
748
|
+
* explicit list of names or a {@link StreamFilter}, mirroring
|
|
749
|
+
* {@link reset}/{@link prioritize}. Cleared by ack/block/reset/unblock.
|
|
750
|
+
*
|
|
751
|
+
* @returns Count of streams whose `deferred_at` was set.
|
|
752
|
+
*/
|
|
753
|
+
async defer(input, deferred_at) {
|
|
754
|
+
const set_clause = `SET deferred_at = to_timestamp($1 / 1000.0), retry = -1`;
|
|
755
|
+
if (Array.isArray(input)) {
|
|
756
|
+
if (!input.length) return 0;
|
|
757
|
+
const { rowCount: rowCount2 } = await this._pool.query(
|
|
758
|
+
`UPDATE ${this._fqs} ${set_clause} WHERE stream = ANY($2)`,
|
|
759
|
+
[deferred_at, input]
|
|
760
|
+
);
|
|
761
|
+
return rowCount2 ?? 0;
|
|
762
|
+
}
|
|
763
|
+
const { clause, values } = this._filter_clause(input, 2);
|
|
764
|
+
const { rowCount } = await this._pool.query(
|
|
765
|
+
`UPDATE ${this._fqs} ${set_clause} WHERE ${clause}`,
|
|
766
|
+
[deferred_at, ...values]
|
|
767
|
+
);
|
|
768
|
+
return rowCount ?? 0;
|
|
769
|
+
}
|
|
693
770
|
/**
|
|
694
771
|
* Reset watermarks for the given streams to -1, clearing retry, blocked,
|
|
695
772
|
* error, and lease state so they can be replayed from the beginning.
|
|
@@ -733,7 +810,7 @@ var PostgresStore = class {
|
|
|
733
810
|
}
|
|
734
811
|
async reset(input) {
|
|
735
812
|
const set_clause = `SET at = -1, retry = -1, blocked = false, error = NULL,
|
|
736
|
-
leased_by = NULL, leased_until = NULL`;
|
|
813
|
+
leased_by = NULL, leased_until = NULL, deferred_at = NULL`;
|
|
737
814
|
if (Array.isArray(input)) {
|
|
738
815
|
if (!input.length) return 0;
|
|
739
816
|
const { rowCount: rowCount2 } = await this._pool.query(
|
|
@@ -766,7 +843,7 @@ var PostgresStore = class {
|
|
|
766
843
|
*/
|
|
767
844
|
async unblock(input) {
|
|
768
845
|
const set_clause = `SET retry = -1, blocked = false, error = NULL,
|
|
769
|
-
leased_by = NULL, leased_until = NULL`;
|
|
846
|
+
leased_by = NULL, leased_until = NULL, deferred_at = NULL`;
|
|
770
847
|
if (Array.isArray(input)) {
|
|
771
848
|
if (!input.length) return 0;
|
|
772
849
|
const { rowCount: rowCount2 } = await this._pool.query(
|
|
@@ -858,7 +935,7 @@ var PostgresStore = class {
|
|
|
858
935
|
if (conditions.length) sql += " WHERE " + conditions.join(" AND ");
|
|
859
936
|
values.push(limit);
|
|
860
937
|
sql += ` ORDER BY stream LIMIT $${values.length}`;
|
|
861
|
-
const client = await this.
|
|
938
|
+
const client = await this._client("query_streams");
|
|
862
939
|
try {
|
|
863
940
|
const [streamsResult, maxResult] = await Promise.all([
|
|
864
941
|
client.query(sql, values),
|
|
@@ -1088,7 +1165,7 @@ var PostgresStore = class {
|
|
|
1088
1165
|
*/
|
|
1089
1166
|
async _subscribe_notifications(handler) {
|
|
1090
1167
|
await this._teardown_listen();
|
|
1091
|
-
const client = await this.
|
|
1168
|
+
const client = await this._client("notify");
|
|
1092
1169
|
const on_notification = (msg) => {
|
|
1093
1170
|
if (msg.channel !== this._channel) return;
|
|
1094
1171
|
if (!msg.payload) return;
|
|
@@ -1149,7 +1226,7 @@ var PostgresStore = class {
|
|
|
1149
1226
|
async truncate(targets) {
|
|
1150
1227
|
if (!targets.length) return /* @__PURE__ */ new Map();
|
|
1151
1228
|
const streams = targets.map((t) => t.stream);
|
|
1152
|
-
const client = await this.
|
|
1229
|
+
const client = await this._client("truncate");
|
|
1153
1230
|
try {
|
|
1154
1231
|
await client.query("BEGIN");
|
|
1155
1232
|
await client.query(`DELETE FROM ${this._fqs} WHERE stream = ANY($1)`, [
|
|
@@ -1200,7 +1277,7 @@ var PostgresStore = class {
|
|
|
1200
1277
|
* from 1. `created` is preserved verbatim from the source.
|
|
1201
1278
|
*/
|
|
1202
1279
|
async restore(driver) {
|
|
1203
|
-
const client = await this.
|
|
1280
|
+
const client = await this._client("restore");
|
|
1204
1281
|
try {
|
|
1205
1282
|
await client.query("BEGIN");
|
|
1206
1283
|
await client.query(
|