@rotorsoft/act-pg 1.14.0 → 1.15.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/dist/.tsbuildinfo +1 -1
- package/dist/@types/postgres-store.d.ts +2 -7
- package/dist/@types/postgres-store.d.ts.map +1 -1
- package/dist/index.cjs +53 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +53 -7
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
|
@@ -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<{
|
|
@@ -326,12 +326,7 @@ export declare class PostgresStore implements Store {
|
|
|
326
326
|
* @param streams - Streams to register with optional source.
|
|
327
327
|
* @returns subscribed count and current max watermark.
|
|
328
328
|
*/
|
|
329
|
-
subscribe(streams:
|
|
330
|
-
stream: string;
|
|
331
|
-
source?: string;
|
|
332
|
-
priority?: number;
|
|
333
|
-
lane?: string;
|
|
334
|
-
}>, correlated_at?: number): Promise<{
|
|
329
|
+
subscribe(streams: SubscribeInput[], correlated_at?: number): Promise<{
|
|
335
330
|
subscribed: number;
|
|
336
331
|
watermark: number;
|
|
337
332
|
correlated_at: number;
|
|
@@ -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
|
@@ -330,13 +330,14 @@ var PostgresStore = class {
|
|
|
330
330
|
leased_until timestamptz,
|
|
331
331
|
priority int NOT NULL DEFAULT 0,
|
|
332
332
|
lane text NOT NULL DEFAULT 'default',
|
|
333
|
-
deferred_at timestamptz
|
|
333
|
+
deferred_at timestamptz,
|
|
334
|
+
correlated_at int
|
|
334
335
|
) TABLESPACE pg_default;`
|
|
335
336
|
);
|
|
336
337
|
await client.query(
|
|
337
338
|
`CREATE TABLE IF NOT EXISTS ${this._fqc} (
|
|
338
339
|
id int PRIMARY KEY DEFAULT 0,
|
|
339
|
-
at
|
|
340
|
+
at int NOT NULL DEFAULT -1,
|
|
340
341
|
CONSTRAINT ${this.config.table}_correlated_singleton CHECK (id = 0)
|
|
341
342
|
) TABLESPACE pg_default;`
|
|
342
343
|
);
|
|
@@ -355,6 +356,10 @@ var PostgresStore = class {
|
|
|
355
356
|
`ALTER TABLE ${this._fqs}
|
|
356
357
|
ADD COLUMN IF NOT EXISTS deferred_at timestamptz;`
|
|
357
358
|
);
|
|
359
|
+
await client.query(
|
|
360
|
+
`ALTER TABLE ${this._fqs}
|
|
361
|
+
ADD COLUMN IF NOT EXISTS correlated_at int;`
|
|
362
|
+
);
|
|
358
363
|
await client.query(
|
|
359
364
|
`DO $$
|
|
360
365
|
BEGIN
|
|
@@ -403,6 +408,11 @@ var PostgresStore = class {
|
|
|
403
408
|
`CREATE INDEX IF NOT EXISTS "${this.config.table}_streams_lane_ix"
|
|
404
409
|
ON ${this._fqs} (lane);`
|
|
405
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
|
+
);
|
|
406
416
|
await client.query("COMMIT");
|
|
407
417
|
logger.info(
|
|
408
418
|
`Seeded schema "${this.config.schema}" with table "${this.config.table}"`
|
|
@@ -679,7 +689,7 @@ var PostgresStore = class {
|
|
|
679
689
|
-- Measured at 10k subscribed streams with 10 pending: 5,792 ms
|
|
680
690
|
-- before, 10.3 ms after. See libs/act-pg/PERFORMANCE.md for #1448.
|
|
681
691
|
eligible AS (
|
|
682
|
-
SELECT stream, source, at, priority, lane
|
|
692
|
+
SELECT stream, source, at, priority, lane, correlated_at
|
|
683
693
|
FROM ${this._fqs} s
|
|
684
694
|
WHERE blocked = false
|
|
685
695
|
${lane_clause}
|
|
@@ -687,6 +697,26 @@ var PostgresStore = class {
|
|
|
687
697
|
AND (deferred_at IS NULL OR deferred_at <= NOW())
|
|
688
698
|
),
|
|
689
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
|
+
--
|
|
690
720
|
-- Every arm below is watermark-agnostic (#1446): a fresh
|
|
691
721
|
-- subscription sits at -1, and e.id > s.at already answers
|
|
692
722
|
-- correctly there, since the first event has a greater id.
|
|
@@ -696,7 +726,8 @@ var PostgresStore = class {
|
|
|
696
726
|
-- Source-less subscription: any non-snapshot event past the
|
|
697
727
|
-- watermark counts, so the id index alone answers it.
|
|
698
728
|
SELECT stream, source, at, priority, lane FROM eligible s
|
|
699
|
-
WHERE s.
|
|
729
|
+
WHERE s.correlated_at IS NULL
|
|
730
|
+
AND s.source IS NULL
|
|
700
731
|
AND EXISTS (
|
|
701
732
|
SELECT 1 FROM ${this._fqt} e
|
|
702
733
|
WHERE e.id > s.at AND e.name <> '${import_act.SNAP_EVENT}' LIMIT 1
|
|
@@ -705,7 +736,8 @@ var PostgresStore = class {
|
|
|
705
736
|
-- Literal source (no regex metacharacter): exact equality, so
|
|
706
737
|
-- "s1" never claims "s12", and (stream, id) is usable.
|
|
707
738
|
SELECT stream, source, at, priority, lane FROM eligible s
|
|
708
|
-
WHERE s.
|
|
739
|
+
WHERE s.correlated_at IS NULL
|
|
740
|
+
AND s.source IS NOT NULL
|
|
709
741
|
AND s.source !~ '${SOURCE_METACHARACTER_CLASS}'
|
|
710
742
|
AND EXISTS (
|
|
711
743
|
SELECT 1 FROM ${this._fqt} e
|
|
@@ -718,7 +750,8 @@ var PostgresStore = class {
|
|
|
718
750
|
-- it anchors. Unavoidably a scan \u2014 but only for the subscriptions
|
|
719
751
|
-- that actually declare a pattern.
|
|
720
752
|
SELECT stream, source, at, priority, lane FROM eligible s
|
|
721
|
-
WHERE s.
|
|
753
|
+
WHERE s.correlated_at IS NULL
|
|
754
|
+
AND s.source IS NOT NULL
|
|
722
755
|
AND s.source ~ '${SOURCE_METACHARACTER_CLASS}'
|
|
723
756
|
AND EXISTS (
|
|
724
757
|
SELECT 1 FROM ${this._fqt} e
|
|
@@ -860,10 +893,23 @@ var PostgresStore = class {
|
|
|
860
893
|
`,
|
|
861
894
|
[JSON.stringify(streams)]
|
|
862
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
|
+
);
|
|
863
909
|
}
|
|
864
910
|
if (correlated_at !== void 0)
|
|
865
911
|
await client.query(
|
|
866
|
-
`UPDATE ${this._fqc} SET at = GREATEST(at, $1::
|
|
912
|
+
`UPDATE ${this._fqc} SET at = GREATEST(at, $1::int) WHERE id = 0`,
|
|
867
913
|
[correlated_at]
|
|
868
914
|
);
|
|
869
915
|
const { rows } = await client.query(
|