@rotorsoft/act-pg 1.13.19 → 1.15.0
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/dist/.tsbuildinfo +1 -1
- package/dist/@types/postgres-store.d.ts +5 -7
- package/dist/@types/postgres-store.d.ts.map +1 -1
- package/dist/index.cjs +78 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +78 -9
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BlockedLease, Committed, EventMeta, Lease, Message, NotifyDisposer, Query, QueryStatsOptions, QueryStreams, QueryStreamsResult, Schema, Schemas, Store, StoreNotification, StreamFilter, StreamPosition, StreamStats } from "@rotorsoft/act";
|
|
1
|
+
import type { BlockedLease, Committed, EventMeta, Lease, Message, NotifyDisposer, Query, QueryStatsOptions, QueryStreams, QueryStreamsResult, Schema, Schemas, Store, StoreNotification, StreamFilter, StreamPosition, StreamStats, SubscribeInput } from "@rotorsoft/act";
|
|
2
2
|
import { type Encryption } from "@rotorsoft/act-crypto";
|
|
3
3
|
import pg from "pg";
|
|
4
4
|
type Config = Readonly<{
|
|
@@ -166,6 +166,8 @@ export declare class PostgresStore implements Store {
|
|
|
166
166
|
readonly config: Config;
|
|
167
167
|
private _fqt;
|
|
168
168
|
private _fqs;
|
|
169
|
+
/** Correlate checkpoint table (#1484) — one row, id 0. */
|
|
170
|
+
private _fqc;
|
|
169
171
|
/**
|
|
170
172
|
* Per-instance writer identifier embedded in every NOTIFY payload. The
|
|
171
173
|
* `notify()` LISTEN handler skips payloads where `by === this._by`,
|
|
@@ -324,14 +326,10 @@ export declare class PostgresStore implements Store {
|
|
|
324
326
|
* @param streams - Streams to register with optional source.
|
|
325
327
|
* @returns subscribed count and current max watermark.
|
|
326
328
|
*/
|
|
327
|
-
subscribe(streams:
|
|
328
|
-
stream: string;
|
|
329
|
-
source?: string;
|
|
330
|
-
priority?: number;
|
|
331
|
-
lane?: string;
|
|
332
|
-
}>): Promise<{
|
|
329
|
+
subscribe(streams: SubscribeInput[], correlated_at?: number): Promise<{
|
|
333
330
|
subscribed: number;
|
|
334
331
|
watermark: number;
|
|
332
|
+
correlated_at: number;
|
|
335
333
|
}>;
|
|
336
334
|
/**
|
|
337
335
|
* Acknowledge and release leases after processing, updating stream positions.
|
|
@@ -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,
|
|
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
|
@@ -108,6 +108,8 @@ var PostgresStore = class {
|
|
|
108
108
|
config;
|
|
109
109
|
_fqt;
|
|
110
110
|
_fqs;
|
|
111
|
+
/** Correlate checkpoint table (#1484) — one row, id 0. */
|
|
112
|
+
_fqc;
|
|
111
113
|
/**
|
|
112
114
|
* Per-instance writer identifier embedded in every NOTIFY payload. The
|
|
113
115
|
* `notify()` LISTEN handler skips payloads where `by === this._by`,
|
|
@@ -194,6 +196,7 @@ var PostgresStore = class {
|
|
|
194
196
|
this._pool = new Pool({ ...poolConfig, types: scopedTypes });
|
|
195
197
|
this._fqt = `"${this.config.schema}"."${this.config.table}"`;
|
|
196
198
|
this._fqs = `"${this.config.schema}"."${this.config.table}_streams"`;
|
|
199
|
+
this._fqc = `"${this.config.schema}"."${this.config.table}_correlated"`;
|
|
197
200
|
this._channel = notify_channel(this.config.schema, this.config.table);
|
|
198
201
|
if (this.config.notify) {
|
|
199
202
|
this.notify = this._subscribe_notifications.bind(this);
|
|
@@ -327,9 +330,20 @@ var PostgresStore = class {
|
|
|
327
330
|
leased_until timestamptz,
|
|
328
331
|
priority int NOT NULL DEFAULT 0,
|
|
329
332
|
lane text NOT NULL DEFAULT 'default',
|
|
330
|
-
deferred_at timestamptz
|
|
333
|
+
deferred_at timestamptz,
|
|
334
|
+
correlated_at int
|
|
331
335
|
) TABLESPACE pg_default;`
|
|
332
336
|
);
|
|
337
|
+
await client.query(
|
|
338
|
+
`CREATE TABLE IF NOT EXISTS ${this._fqc} (
|
|
339
|
+
id int PRIMARY KEY DEFAULT 0,
|
|
340
|
+
at int NOT NULL DEFAULT -1,
|
|
341
|
+
CONSTRAINT ${this.config.table}_correlated_singleton CHECK (id = 0)
|
|
342
|
+
) TABLESPACE pg_default;`
|
|
343
|
+
);
|
|
344
|
+
await client.query(
|
|
345
|
+
`INSERT INTO ${this._fqc} (id) VALUES (0) ON CONFLICT (id) DO NOTHING;`
|
|
346
|
+
);
|
|
333
347
|
await client.query(
|
|
334
348
|
`ALTER TABLE ${this._fqs}
|
|
335
349
|
ADD COLUMN IF NOT EXISTS priority int NOT NULL DEFAULT 0;`
|
|
@@ -342,6 +356,10 @@ var PostgresStore = class {
|
|
|
342
356
|
`ALTER TABLE ${this._fqs}
|
|
343
357
|
ADD COLUMN IF NOT EXISTS deferred_at timestamptz;`
|
|
344
358
|
);
|
|
359
|
+
await client.query(
|
|
360
|
+
`ALTER TABLE ${this._fqs}
|
|
361
|
+
ADD COLUMN IF NOT EXISTS correlated_at int;`
|
|
362
|
+
);
|
|
345
363
|
await client.query(
|
|
346
364
|
`DO $$
|
|
347
365
|
BEGIN
|
|
@@ -390,6 +408,11 @@ var PostgresStore = class {
|
|
|
390
408
|
`CREATE INDEX IF NOT EXISTS "${this.config.table}_streams_lane_ix"
|
|
391
409
|
ON ${this._fqs} (lane);`
|
|
392
410
|
);
|
|
411
|
+
await client.query(
|
|
412
|
+
`CREATE INDEX IF NOT EXISTS "${this.config.table}_streams_correlated_at_ix"
|
|
413
|
+
ON ${this._fqs} (lane, priority DESC, at)
|
|
414
|
+
WHERE blocked = false AND at < correlated_at;`
|
|
415
|
+
);
|
|
393
416
|
await client.query("COMMIT");
|
|
394
417
|
logger.info(
|
|
395
418
|
`Seeded schema "${this.config.schema}" with table "${this.config.table}"`
|
|
@@ -415,7 +438,7 @@ var PostgresStore = class {
|
|
|
415
438
|
WHERE schema_name = '${this.config.schema}'
|
|
416
439
|
) THEN
|
|
417
440
|
EXECUTE 'DROP TABLE IF EXISTS ${this._fqt}';
|
|
418
|
-
EXECUTE 'DROP TABLE IF EXISTS ${this._fqs}';
|
|
441
|
+
EXECUTE 'DROP TABLE IF EXISTS ${this._fqc}, ${this._fqs}';
|
|
419
442
|
IF '${this.config.schema}' <> 'public' THEN
|
|
420
443
|
EXECUTE 'DROP SCHEMA "${this.config.schema}" CASCADE';
|
|
421
444
|
END IF;
|
|
@@ -666,7 +689,7 @@ var PostgresStore = class {
|
|
|
666
689
|
-- Measured at 10k subscribed streams with 10 pending: 5,792 ms
|
|
667
690
|
-- before, 10.3 ms after. See libs/act-pg/PERFORMANCE.md for #1448.
|
|
668
691
|
eligible AS (
|
|
669
|
-
SELECT stream, source, at, priority, lane
|
|
692
|
+
SELECT stream, source, at, priority, lane, correlated_at
|
|
670
693
|
FROM ${this._fqs} s
|
|
671
694
|
WHERE blocked = false
|
|
672
695
|
${lane_clause}
|
|
@@ -674,6 +697,26 @@ var PostgresStore = class {
|
|
|
674
697
|
AND (deferred_at IS NULL OR deferred_at <= NOW())
|
|
675
698
|
),
|
|
676
699
|
available AS (
|
|
700
|
+
-- Fast arm (#1485): a marked stream answers from the subscription
|
|
701
|
+
-- row alone. Read from the base table, NOT from the eligible CTE:
|
|
702
|
+
-- it is referenced several times so PG materializes it, and a
|
|
703
|
+
-- materialized scan cannot use the partial index this predicate was
|
|
704
|
+
-- built for (WHERE blocked = false AND at < correlated_at).
|
|
705
|
+
-- The comparison is NULL-safe: an unmarked row compares
|
|
706
|
+
-- unknown and is excluded here, falling through to the legacy arms.
|
|
707
|
+
SELECT stream, source, at, priority, lane
|
|
708
|
+
FROM ${this._fqs} s
|
|
709
|
+
WHERE s.blocked = false
|
|
710
|
+
AND s.at < s.correlated_at
|
|
711
|
+
${lane_clause}
|
|
712
|
+
AND (s.leased_by IS NULL OR s.leased_until <= NOW())
|
|
713
|
+
AND (s.deferred_at IS NULL OR s.deferred_at <= NOW())
|
|
714
|
+
UNION ALL
|
|
715
|
+
-- Legacy arms, gated on an absent mark. NULL means "unknown", so
|
|
716
|
+
-- an install that predates the column probes the event log exactly
|
|
717
|
+
-- as it did before, and each row migrates to the fast arm the first
|
|
718
|
+
-- time correlate marks it. Deleted once correlate marks universally.
|
|
719
|
+
--
|
|
677
720
|
-- Every arm below is watermark-agnostic (#1446): a fresh
|
|
678
721
|
-- subscription sits at -1, and e.id > s.at already answers
|
|
679
722
|
-- correctly there, since the first event has a greater id.
|
|
@@ -683,7 +726,8 @@ var PostgresStore = class {
|
|
|
683
726
|
-- Source-less subscription: any non-snapshot event past the
|
|
684
727
|
-- watermark counts, so the id index alone answers it.
|
|
685
728
|
SELECT stream, source, at, priority, lane FROM eligible s
|
|
686
|
-
WHERE s.
|
|
729
|
+
WHERE s.correlated_at IS NULL
|
|
730
|
+
AND s.source IS NULL
|
|
687
731
|
AND EXISTS (
|
|
688
732
|
SELECT 1 FROM ${this._fqt} e
|
|
689
733
|
WHERE e.id > s.at AND e.name <> '${import_act.SNAP_EVENT}' LIMIT 1
|
|
@@ -692,7 +736,8 @@ var PostgresStore = class {
|
|
|
692
736
|
-- Literal source (no regex metacharacter): exact equality, so
|
|
693
737
|
-- "s1" never claims "s12", and (stream, id) is usable.
|
|
694
738
|
SELECT stream, source, at, priority, lane FROM eligible s
|
|
695
|
-
WHERE s.
|
|
739
|
+
WHERE s.correlated_at IS NULL
|
|
740
|
+
AND s.source IS NOT NULL
|
|
696
741
|
AND s.source !~ '${SOURCE_METACHARACTER_CLASS}'
|
|
697
742
|
AND EXISTS (
|
|
698
743
|
SELECT 1 FROM ${this._fqt} e
|
|
@@ -705,7 +750,8 @@ var PostgresStore = class {
|
|
|
705
750
|
-- it anchors. Unavoidably a scan \u2014 but only for the subscriptions
|
|
706
751
|
-- that actually declare a pattern.
|
|
707
752
|
SELECT stream, source, at, priority, lane FROM eligible s
|
|
708
|
-
WHERE s.
|
|
753
|
+
WHERE s.correlated_at IS NULL
|
|
754
|
+
AND s.source IS NOT NULL
|
|
709
755
|
AND s.source ~ '${SOURCE_METACHARACTER_CLASS}'
|
|
710
756
|
AND EXISTS (
|
|
711
757
|
SELECT 1 FROM ${this._fqt} e
|
|
@@ -807,7 +853,7 @@ var PostgresStore = class {
|
|
|
807
853
|
* @param streams - Streams to register with optional source.
|
|
808
854
|
* @returns subscribed count and current max watermark.
|
|
809
855
|
*/
|
|
810
|
-
async subscribe(streams) {
|
|
856
|
+
async subscribe(streams, correlated_at) {
|
|
811
857
|
const client = await this._client("subscribe");
|
|
812
858
|
try {
|
|
813
859
|
await client.query("BEGIN");
|
|
@@ -847,12 +893,35 @@ var PostgresStore = class {
|
|
|
847
893
|
`,
|
|
848
894
|
[JSON.stringify(streams)]
|
|
849
895
|
);
|
|
896
|
+
if (streams.some((s) => s.correlated_at !== void 0))
|
|
897
|
+
await client.query(
|
|
898
|
+
`
|
|
899
|
+
UPDATE ${this._fqs} t
|
|
900
|
+
SET correlated_at = (s->>'correlated_at')::int
|
|
901
|
+
FROM jsonb_array_elements($1::jsonb) AS s
|
|
902
|
+
WHERE t.stream = s->>'stream'
|
|
903
|
+
AND s->>'correlated_at' IS NOT NULL
|
|
904
|
+
AND (t.correlated_at IS NULL
|
|
905
|
+
OR t.correlated_at < (s->>'correlated_at')::int)
|
|
906
|
+
`,
|
|
907
|
+
[JSON.stringify(streams)]
|
|
908
|
+
);
|
|
850
909
|
}
|
|
910
|
+
if (correlated_at !== void 0)
|
|
911
|
+
await client.query(
|
|
912
|
+
`UPDATE ${this._fqc} SET at = GREATEST(at, $1::int) WHERE id = 0`,
|
|
913
|
+
[correlated_at]
|
|
914
|
+
);
|
|
851
915
|
const { rows } = await client.query(
|
|
852
|
-
`SELECT COALESCE(MAX(at), -1)
|
|
916
|
+
`SELECT (SELECT COALESCE(MAX(at), -1) FROM ${this._fqs}) AS max,
|
|
917
|
+
(SELECT at FROM ${this._fqc} WHERE id = 0) AS correlated_at`
|
|
853
918
|
);
|
|
854
919
|
await client.query("COMMIT");
|
|
855
|
-
return {
|
|
920
|
+
return {
|
|
921
|
+
subscribed,
|
|
922
|
+
watermark: rows[0]?.max ?? -1,
|
|
923
|
+
correlated_at: Number(rows[0]?.correlated_at ?? -1)
|
|
924
|
+
};
|
|
856
925
|
} catch (error) {
|
|
857
926
|
await client.query("ROLLBACK").catch(() => {
|
|
858
927
|
});
|