@rotorsoft/act-pg 1.17.0 → 1.17.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/index.js CHANGED
@@ -393,6 +393,11 @@ var PostgresStore = class {
393
393
  ON ${this._fqs} (lane, priority DESC, at)
394
394
  WHERE blocked = false AND at < correlated_at;`
395
395
  );
396
+ await client.query(
397
+ `CREATE INDEX IF NOT EXISTS "${this.config.table}_streams_at_ix"
398
+ ON ${this._fqs} (at)
399
+ WHERE blocked = false AND at < correlated_at;`
400
+ );
396
401
  await client.query("COMMIT");
397
402
  logger.info(
398
403
  `Seeded schema "${this.config.schema}" with table "${this.config.table}"`
@@ -661,67 +666,64 @@ var PostgresStore = class {
661
666
  -- cost O(subscribed streams) per claim per worker no matter how
662
667
  -- little work was pending.
663
668
  --
664
- -- Read from the base table so the planner can use the partial index
665
- -- built for exactly this predicate:
666
- -- (lane, priority DESC, at) WHERE blocked = false
667
- -- AND at < correlated_at
668
- -- It contains only streams with work, so LIMIT pushes into it and a
669
- -- claim scans at most lagging + leading rows. A stream leaves the
670
- -- index when ack advances at to the mark, and re-enters when
671
- -- correlate raises it.
669
+ -- The predicate is repeated in each arm below rather than factored
670
+ -- into a shared CTE, and that repetition is load-bearing (#1510). A
671
+ -- CTE referenced more than once is materialized, so LIMIT 8 was
672
+ -- applied to a fully-built 100,000-row result instead of pushing into
673
+ -- the index: measured at 75.6 ms for a claim that returns 8 rows.
674
+ -- Reading the base table in each arm lets the planner stop after the
675
+ -- limit \u2014 19.9 ms with the existing index, 2.0 ms once the
676
+ -- at-ordered partial index below serves the two watermark arms.
677
+ --
678
+ -- A row with no mark compares unknown and is excluded by SQL's own
679
+ -- rules. That is definitional (#1446): a subscription is claimable iff
680
+ -- a mark says so. seed() marks rows that predate the column.
681
+ --
682
+ -- Priority lanes (ACT-102): higher priority first, then
683
+ -- lagging-watermark order. With everyone at priority=0 the ORDER BY
684
+ -- collapses to plain at ASC, so existing workloads see no change.
672
685
  --
673
- -- The comparison is NULL-safe by SQL's own rules: an unmarked row
674
- -- compares unknown and is excluded. That is definitional now
675
- -- (#1446) \u2014 a subscription is claimable iff a mark says so \u2014 where
676
- -- before #1488 it meant "unknown, fall through to the probe". An
677
- -- install upgrading from before the column needs one correlate pass
678
- -- from a rewound checkpoint to mark its rows; see the runbook in
679
- -- docs/docs/guides/production-checklist.md.
680
- available AS (
681
- SELECT stream, source, at, priority, lane
686
+ -- The lagging frontier is a UNION of two portions (ACT-1223): the
687
+ -- priority portion takes the first (lagging - fair) slots by
688
+ -- priority DESC, at ASC; a fairness reserve then fills fair more
689
+ -- by pure at ASC (priority ignored), excluding the ones already
690
+ -- chosen, so a default-priority lagging stream is never starved out
691
+ -- by sustained higher-priority load.
692
+ prio AS (
693
+ SELECT stream, source, at, lane, TRUE AS lagging
682
694
  FROM ${this._fqs} s
683
695
  WHERE s.blocked = false
684
696
  AND s.at < s.correlated_at
685
697
  ${lane_clause}
686
698
  AND (s.leased_by IS NULL OR s.leased_until <= NOW())
687
699
  AND (s.deferred_at IS NULL OR s.deferred_at <= NOW())
700
+ ORDER BY s.priority DESC, s.at ASC
701
+ LIMIT ($1::int - $5::int)
702
+ ),
703
+ fair AS (
704
+ SELECT stream, source, at, lane, TRUE AS lagging
705
+ FROM ${this._fqs} s
706
+ WHERE s.blocked = false
707
+ AND s.at < s.correlated_at
708
+ ${lane_clause}
709
+ AND (s.leased_by IS NULL OR s.leased_until <= NOW())
710
+ AND (s.deferred_at IS NULL OR s.deferred_at <= NOW())
711
+ AND s.stream NOT IN (SELECT stream FROM prio)
712
+ ORDER BY s.at ASC
713
+ LIMIT $5
688
714
  ),
689
- -- Priority lanes (ACT-102): higher priority first, then
690
- -- lagging-watermark order. With everyone at priority=0 the
691
- -- ORDER BY collapses to plain at ASC so existing workloads
692
- -- see no behavior change.
693
- --
694
- -- The lagging frontier is a UNION of two portions (ACT-1223): the
695
- -- priority-ordered portion takes the first (lagging - fair) slots
696
- -- by priority DESC, at ASC; a fairness reserve then fills fair more
697
- -- slots by pure at ASC (priority ignored), excluding the ones
698
- -- already chosen, so a default-priority lagging stream is never
699
- -- starved out by sustained higher-priority load. With all
700
- -- priorities equal both portions order by at, a no-op merge.
701
715
  lag AS (
702
- (
703
- SELECT stream, source, at, lane, TRUE AS lagging
704
- FROM available
705
- ORDER BY priority DESC, at ASC
706
- LIMIT ($1::int - $5::int)
707
- )
708
- UNION
709
- (
710
- SELECT stream, source, at, lane, TRUE AS lagging
711
- FROM available
712
- WHERE stream NOT IN (
713
- SELECT stream FROM available
714
- ORDER BY priority DESC, at ASC
715
- LIMIT ($1::int - $5::int)
716
- )
717
- ORDER BY at ASC
718
- LIMIT $5
719
- )
716
+ SELECT * FROM prio UNION SELECT * FROM fair
720
717
  ),
721
718
  lead AS (
722
719
  SELECT stream, source, at, lane, FALSE AS lagging
723
- FROM available
724
- ORDER BY at DESC
720
+ FROM ${this._fqs} s
721
+ WHERE s.blocked = false
722
+ AND s.at < s.correlated_at
723
+ ${lane_clause}
724
+ AND (s.leased_by IS NULL OR s.leased_until <= NOW())
725
+ AND (s.deferred_at IS NULL OR s.deferred_at <= NOW())
726
+ ORDER BY s.at DESC
725
727
  LIMIT $2
726
728
  ),
727
729
  combined AS (