@rotorsoft/act 1.27.0 → 1.28.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/act.d.ts +20 -2
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/adapters/in-memory-store.d.ts.map +1 -1
- package/dist/@types/internal/build-classify.d.ts +4 -6
- package/dist/@types/internal/build-classify.d.ts.map +1 -1
- package/dist/@types/internal/close-cycle.d.ts +19 -0
- package/dist/@types/internal/close-cycle.d.ts.map +1 -1
- package/dist/@types/internal/correlate-cycle.d.ts +30 -20
- package/dist/@types/internal/correlate-cycle.d.ts.map +1 -1
- package/dist/@types/internal/settle.d.ts +0 -10
- package/dist/@types/internal/settle.d.ts.map +1 -1
- package/dist/@types/types/ports.d.ts +8 -0
- package/dist/@types/types/ports.d.ts.map +1 -1
- package/dist/{chunk-66PTM4QB.js → chunk-7WFKIQKY.js} +3 -2
- package/dist/{chunk-66PTM4QB.js.map → chunk-7WFKIQKY.js.map} +1 -1
- package/dist/index.cjs +131 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +130 -75
- package/dist/index.js.map +1 -1
- package/dist/test/index.cjs +2 -1
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.js +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
sleep,
|
|
23
23
|
store,
|
|
24
24
|
validate
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-7WFKIQKY.js";
|
|
26
26
|
import {
|
|
27
27
|
ActorSchema,
|
|
28
28
|
CausationEventSchema,
|
|
@@ -829,12 +829,10 @@ function classify_registry(registry, states) {
|
|
|
829
829
|
const target_lanes = /* @__PURE__ */ new Map();
|
|
830
830
|
const reactive_events = /* @__PURE__ */ new Set();
|
|
831
831
|
const event_to_lanes = /* @__PURE__ */ new Map();
|
|
832
|
-
let has_dynamic_resolvers = false;
|
|
833
832
|
for (const [name, register] of Object.entries(registry.events)) {
|
|
834
833
|
if (register.reactions.size > 0) reactive_events.add(name);
|
|
835
834
|
for (const reaction of register.reactions.values()) {
|
|
836
835
|
if (typeof reaction.resolver === "function") {
|
|
837
|
-
has_dynamic_resolvers = true;
|
|
838
836
|
event_to_lanes.set(name, ALL_LANES);
|
|
839
837
|
} else {
|
|
840
838
|
const { target, source, priority = 0, lane } = reaction.resolver;
|
|
@@ -870,7 +868,6 @@ function classify_registry(registry, states) {
|
|
|
870
868
|
}
|
|
871
869
|
return {
|
|
872
870
|
static_targets: [...statics.values()],
|
|
873
|
-
has_dynamic_resolvers,
|
|
874
871
|
reactive_events,
|
|
875
872
|
event_to_state,
|
|
876
873
|
event_to_lanes
|
|
@@ -1354,7 +1351,8 @@ async function run_close_cycle(targets, deps) {
|
|
|
1354
1351
|
stream_info,
|
|
1355
1352
|
deps.reactive_events_size,
|
|
1356
1353
|
skipped,
|
|
1357
|
-
deps.probe_page_size ?? SAFETY_PROBE_PAGE_SIZE
|
|
1354
|
+
deps.probe_page_size ?? SAFETY_PROBE_PAGE_SIZE,
|
|
1355
|
+
deps.catch_up_correlation
|
|
1358
1356
|
);
|
|
1359
1357
|
if (!safe.length) return { truncated: windowed_result, skipped };
|
|
1360
1358
|
const { guarded, guard_events } = await guard_with_tombstones(
|
|
@@ -1473,8 +1471,16 @@ async function scan_stream_heads(streams) {
|
|
|
1473
1471
|
}
|
|
1474
1472
|
return out;
|
|
1475
1473
|
}
|
|
1476
|
-
async function partition_by_safety(stream_info, reactive_events_size, skipped, page_size) {
|
|
1474
|
+
async function partition_by_safety(stream_info, reactive_events_size, skipped, page_size, catch_up_correlation) {
|
|
1477
1475
|
if (reactive_events_size === 0) return [...stream_info.keys()];
|
|
1476
|
+
let needed = -1;
|
|
1477
|
+
for (const info of stream_info.values())
|
|
1478
|
+
needed = Math.max(needed, info.max_id);
|
|
1479
|
+
const checkpoint = await catch_up_correlation(needed);
|
|
1480
|
+
const uncorrelated = /* @__PURE__ */ new Set();
|
|
1481
|
+
for (const [stream, info] of stream_info) {
|
|
1482
|
+
if (checkpoint < info.max_id) uncorrelated.add(stream);
|
|
1483
|
+
}
|
|
1478
1484
|
const pending_set = /* @__PURE__ */ new Set();
|
|
1479
1485
|
const source_regex = /* @__PURE__ */ new Map();
|
|
1480
1486
|
const get_regex = (source) => {
|
|
@@ -1493,6 +1499,8 @@ async function partition_by_safety(stream_info, reactive_events_size, skipped, p
|
|
|
1493
1499
|
(position) => {
|
|
1494
1500
|
last = position.stream;
|
|
1495
1501
|
const source_re = position.source ? get_regex(position.source) : void 0;
|
|
1502
|
+
const has_work = position.correlated_at === void 0 || position.at < position.correlated_at;
|
|
1503
|
+
if (!has_work) return;
|
|
1496
1504
|
for (const [stream, info] of stream_info) {
|
|
1497
1505
|
if ((!source_re || source_re.test(stream)) && position.at < info.max_id) {
|
|
1498
1506
|
pending_set.add(stream);
|
|
@@ -1506,7 +1514,8 @@ async function partition_by_safety(stream_info, reactive_events_size, skipped, p
|
|
|
1506
1514
|
}
|
|
1507
1515
|
const safe = [];
|
|
1508
1516
|
for (const [stream] of stream_info) {
|
|
1509
|
-
if (pending_set.has(stream)
|
|
1517
|
+
if (pending_set.has(stream) || uncorrelated.has(stream))
|
|
1518
|
+
skipped.push(stream);
|
|
1510
1519
|
else safe.push(stream);
|
|
1511
1520
|
}
|
|
1512
1521
|
return safe;
|
|
@@ -1596,21 +1605,24 @@ async function truncate_and_warm_cache(guarded, seed_states, guard_events, corre
|
|
|
1596
1605
|
|
|
1597
1606
|
// src/internal/correlate-cycle.ts
|
|
1598
1607
|
var DEFAULT_COLD_START_BACK_SCAN = 1e4;
|
|
1608
|
+
var PATTERN_CACHE_SIZE = 32;
|
|
1599
1609
|
var CorrelateCycle = class {
|
|
1600
1610
|
_checkpoint = -1;
|
|
1601
1611
|
_initialized = false;
|
|
1602
1612
|
/** In-flight init, memoized for single-flight and cleared on failure. */
|
|
1603
1613
|
_init_promise;
|
|
1604
1614
|
_timer = void 0;
|
|
1605
|
-
// target →
|
|
1606
|
-
//
|
|
1607
|
-
//
|
|
1608
|
-
//
|
|
1609
|
-
//
|
|
1615
|
+
// target → what it was last subscribed at. Every scan re-subscribes the
|
|
1616
|
+
// targets it resolved (that is how the work mark lands), so this no longer
|
|
1617
|
+
// decides *whether* a target is sent — it decides *what* is sent with it:
|
|
1618
|
+
// a resolution raises priority/lane only when it beats the recorded floor,
|
|
1619
|
+
// and otherwise re-sends the row's own values so the mark changes nothing
|
|
1620
|
+
// else. See {@link Subscription}.
|
|
1610
1621
|
_subscribed;
|
|
1622
|
+
/** Compiled pattern sources, bounded by {@link PATTERN_CACHE_SIZE}. */
|
|
1623
|
+
_patterns = new LruMap(PATTERN_CACHE_SIZE);
|
|
1611
1624
|
_registry;
|
|
1612
1625
|
_static_targets;
|
|
1613
|
-
_has_dynamic_resolvers;
|
|
1614
1626
|
_cd;
|
|
1615
1627
|
_on_init;
|
|
1616
1628
|
/**
|
|
@@ -1640,7 +1652,6 @@ var CorrelateCycle = class {
|
|
|
1640
1652
|
constructor({
|
|
1641
1653
|
registry,
|
|
1642
1654
|
static_targets,
|
|
1643
|
-
has_dynamic_resolvers,
|
|
1644
1655
|
cd,
|
|
1645
1656
|
max_subscribed_streams,
|
|
1646
1657
|
run_scoped,
|
|
@@ -1651,7 +1662,6 @@ var CorrelateCycle = class {
|
|
|
1651
1662
|
this._subscribed = new LruMap(max_subscribed_streams);
|
|
1652
1663
|
this._registry = registry;
|
|
1653
1664
|
this._static_targets = static_targets;
|
|
1654
|
-
this._has_dynamic_resolvers = has_dynamic_resolvers;
|
|
1655
1665
|
this._cd = cd;
|
|
1656
1666
|
this._on_init = on_init;
|
|
1657
1667
|
this._run_scoped = run_scoped;
|
|
@@ -1662,19 +1672,10 @@ var CorrelateCycle = class {
|
|
|
1662
1672
|
get checkpoint() {
|
|
1663
1673
|
return this._checkpoint;
|
|
1664
1674
|
}
|
|
1665
|
-
/**
|
|
1666
|
-
* Whether any reaction uses a dynamic resolver — i.e. whether `correlate`
|
|
1667
|
-
* performs a store scan rather than the static no-op early-return. The
|
|
1668
|
-
* settle loop reads this to avoid recording a fictitious circuit-breaker
|
|
1669
|
-
* success on a static app whose correlate never touches the store (#1329).
|
|
1670
|
-
*/
|
|
1671
|
-
get has_dynamic_resolvers() {
|
|
1672
|
-
return this._has_dynamic_resolvers;
|
|
1673
|
-
}
|
|
1674
1675
|
/**
|
|
1675
1676
|
* Initialize correlation state on first call.
|
|
1676
|
-
* - Reads max(at) from store,
|
|
1677
|
-
* `watermark - back_scan`
|
|
1677
|
+
* - Reads the durable correlate checkpoint (and max(at)) from the store,
|
|
1678
|
+
* flooring a first boot at `watermark - back_scan` so an event
|
|
1678
1679
|
* committed-but-not-correlated before a crash is re-scanned on
|
|
1679
1680
|
* restart instead of skipped (ACT-1207)
|
|
1680
1681
|
* - Subscribes static resolver targets (idempotent upsert)
|
|
@@ -1696,10 +1697,14 @@ var CorrelateCycle = class {
|
|
|
1696
1697
|
const { watermark, correlated_at } = await store().subscribe([
|
|
1697
1698
|
...this._static_targets
|
|
1698
1699
|
]);
|
|
1699
|
-
this._checkpoint =
|
|
1700
|
+
this._checkpoint = correlated_at >= 0 ? correlated_at : Math.max(-1, watermark - this._cold_start_back_scan);
|
|
1700
1701
|
this._on_init?.();
|
|
1701
|
-
for (const { stream } of this._static_targets) {
|
|
1702
|
-
this._subscribed.set(stream,
|
|
1702
|
+
for (const { stream, priority = 0, lane } of this._static_targets) {
|
|
1703
|
+
this._subscribed.set(stream, {
|
|
1704
|
+
floor: Number.POSITIVE_INFINITY,
|
|
1705
|
+
priority,
|
|
1706
|
+
lane
|
|
1707
|
+
});
|
|
1703
1708
|
}
|
|
1704
1709
|
await this._on_init_async?.();
|
|
1705
1710
|
}
|
|
@@ -1724,14 +1729,34 @@ var CorrelateCycle = class {
|
|
|
1724
1729
|
}
|
|
1725
1730
|
}
|
|
1726
1731
|
/**
|
|
1727
|
-
*
|
|
1728
|
-
*
|
|
1729
|
-
*
|
|
1732
|
+
* Would an event from `stream` be fetched for a target subscribed with
|
|
1733
|
+
* `source`? The subscription's source is the filter `fetch` queries with
|
|
1734
|
+
* — literal names by equality, patterns compiled as a `RegExp` — so an
|
|
1735
|
+
* event outside it is not work for that target and must not mark it.
|
|
1736
|
+
* No source means the target consumes every stream.
|
|
1737
|
+
*/
|
|
1738
|
+
_in_fetch_window(source, stream) {
|
|
1739
|
+
if (source === void 0 || source === stream) return true;
|
|
1740
|
+
if (is_literal_source(source)) return false;
|
|
1741
|
+
let pattern = this._patterns.get(source);
|
|
1742
|
+
if (!pattern) {
|
|
1743
|
+
pattern = new RegExp(source);
|
|
1744
|
+
this._patterns.set(source, pattern);
|
|
1745
|
+
}
|
|
1746
|
+
return pattern.test(stream);
|
|
1747
|
+
}
|
|
1748
|
+
/**
|
|
1749
|
+
* Scan the events past the checkpoint, resolve each to its target
|
|
1750
|
+
* streams, and record what it found through `cd.subscribe` — new dynamic
|
|
1751
|
+
* targets get registered, and every target an event resolved to gets its
|
|
1752
|
+
* **work mark** raised to that event's id (#1487).
|
|
1753
|
+
*
|
|
1754
|
+
* Both resolver kinds are walked. A static target is already subscribed
|
|
1755
|
+
* at init, but marking it is what makes it claimable without probing the
|
|
1756
|
+
* event log, so the scan runs for every app.
|
|
1730
1757
|
*/
|
|
1731
1758
|
async correlate(query = { after: -1, limit: 10 }) {
|
|
1732
1759
|
await this.init();
|
|
1733
|
-
if (!this._has_dynamic_resolvers)
|
|
1734
|
-
return { subscribed: 0, last_id: this._checkpoint };
|
|
1735
1760
|
const after = Math.max(this._checkpoint, query.after || -1);
|
|
1736
1761
|
const correlated = /* @__PURE__ */ new Map();
|
|
1737
1762
|
let last_id = after;
|
|
@@ -1741,47 +1766,53 @@ var CorrelateCycle = class {
|
|
|
1741
1766
|
const register = this._registry.events[event.name];
|
|
1742
1767
|
if (register) {
|
|
1743
1768
|
for (const reaction of register.reactions.values()) {
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
entry.
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
event
|
|
1762
|
-
});
|
|
1763
|
-
correlated.set(resolved.target, entry);
|
|
1769
|
+
const resolved = typeof reaction.resolver === "function" ? reaction.resolver(event) : reaction.resolver;
|
|
1770
|
+
if (!resolved) continue;
|
|
1771
|
+
const recorded = this._subscribed.get(resolved.target);
|
|
1772
|
+
const priority = resolved.priority ?? 0;
|
|
1773
|
+
const upgraded = !recorded || priority > recorded.floor;
|
|
1774
|
+
const carried = upgraded ? { priority, lane: resolved.lane } : { priority: recorded.priority, lane: recorded.lane };
|
|
1775
|
+
const entry = correlated.get(resolved.target) || {
|
|
1776
|
+
source: resolved.source,
|
|
1777
|
+
priority: carried.priority,
|
|
1778
|
+
lane: carried.lane,
|
|
1779
|
+
upgraded,
|
|
1780
|
+
correlated_at: void 0
|
|
1781
|
+
};
|
|
1782
|
+
if (carried.priority > entry.priority) {
|
|
1783
|
+
entry.priority = carried.priority;
|
|
1784
|
+
entry.lane = carried.lane;
|
|
1785
|
+
entry.upgraded = upgraded;
|
|
1764
1786
|
}
|
|
1787
|
+
if (this._in_fetch_window(resolved.source, event.stream))
|
|
1788
|
+
entry.correlated_at = event.id;
|
|
1789
|
+
correlated.set(resolved.target, entry);
|
|
1765
1790
|
}
|
|
1766
1791
|
}
|
|
1767
1792
|
},
|
|
1768
1793
|
{ ...query, after }
|
|
1769
1794
|
);
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1795
|
+
const streams = [];
|
|
1796
|
+
for (const [stream, entry] of correlated) {
|
|
1797
|
+
if (entry.upgraded || entry.correlated_at !== void 0)
|
|
1798
|
+
streams.push({
|
|
1773
1799
|
stream,
|
|
1774
|
-
source,
|
|
1775
|
-
priority,
|
|
1776
|
-
lane
|
|
1777
|
-
|
|
1778
|
-
|
|
1800
|
+
source: entry.source,
|
|
1801
|
+
priority: entry.priority,
|
|
1802
|
+
lane: entry.lane,
|
|
1803
|
+
correlated_at: entry.correlated_at
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
if (streams.length) {
|
|
1779
1807
|
const { subscribed } = await this._cd.subscribe(streams, last_id);
|
|
1780
1808
|
this._checkpoint = last_id;
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
this._subscribed.set(stream,
|
|
1784
|
-
|
|
1809
|
+
for (const { stream, priority, lane } of streams) {
|
|
1810
|
+
if (correlated.get(stream)?.upgraded)
|
|
1811
|
+
this._subscribed.set(stream, {
|
|
1812
|
+
floor: priority,
|
|
1813
|
+
priority,
|
|
1814
|
+
lane
|
|
1815
|
+
});
|
|
1785
1816
|
}
|
|
1786
1817
|
return { subscribed, last_id };
|
|
1787
1818
|
}
|
|
@@ -3089,7 +3120,7 @@ var SettleLoop = class {
|
|
|
3089
3120
|
...correlate_query,
|
|
3090
3121
|
after: after_before
|
|
3091
3122
|
});
|
|
3092
|
-
|
|
3123
|
+
this._deps.breaker.passed();
|
|
3093
3124
|
const drain = await this._deps.drain(drain_options);
|
|
3094
3125
|
settled_drain = settled_drain ? {
|
|
3095
3126
|
fetched: [...settled_drain.fetched, ...drain.fetched],
|
|
@@ -3135,6 +3166,8 @@ var SettleLoop = class {
|
|
|
3135
3166
|
|
|
3136
3167
|
// src/act.ts
|
|
3137
3168
|
var DEFAULT_MAX_SUBSCRIBED_STREAMS = 1e3;
|
|
3169
|
+
var CLOSE_CATCH_UP_LIMIT = 1e3;
|
|
3170
|
+
var CLOSE_CATCH_UP_PASSES = 20;
|
|
3138
3171
|
var DEFAULT_SETTLE_DEBOUNCE_MS = 10;
|
|
3139
3172
|
function validate_only_lanes(options, lanes) {
|
|
3140
3173
|
if (!options.onlyLanes || options.onlyLanes.length === 0) return;
|
|
@@ -3450,6 +3483,7 @@ var Act = class {
|
|
|
3450
3483
|
const close_actor = { id: "$close", name: "close" };
|
|
3451
3484
|
const result = await run_close_cycle(targets, {
|
|
3452
3485
|
reactive_events_size: this._reactive_events.size,
|
|
3486
|
+
catch_up_correlation: (until) => this._catch_up_correlation(until),
|
|
3453
3487
|
event_to_state: this._event_to_state,
|
|
3454
3488
|
load: this._es.load,
|
|
3455
3489
|
tombstone: this._es.tombstone,
|
|
@@ -3536,7 +3570,6 @@ var Act = class {
|
|
|
3536
3570
|
return new CorrelateCycle({
|
|
3537
3571
|
registry: this.registry,
|
|
3538
3572
|
static_targets: classification.static_targets,
|
|
3539
|
-
has_dynamic_resolvers: classification.has_dynamic_resolvers,
|
|
3540
3573
|
cd: this._cd,
|
|
3541
3574
|
max_subscribed_streams: options.maxSubscribedStreams ?? DEFAULT_MAX_SUBSCRIBED_STREAMS,
|
|
3542
3575
|
on_init: () => {
|
|
@@ -3587,11 +3620,7 @@ var Act = class {
|
|
|
3587
3620
|
correlate: (q) => this.correlate(q),
|
|
3588
3621
|
drain: (o) => this.drain(o),
|
|
3589
3622
|
on_settled: (drain) => this.emit("settled", drain),
|
|
3590
|
-
breaker: this._breaker
|
|
3591
|
-
// Static-reaction apps' correlate is a no-op (no store call), so a
|
|
3592
|
-
// settle pass carries no store-health signal — don't let it record a
|
|
3593
|
-
// breaker success (#1329).
|
|
3594
|
-
correlate_probes_store: this._correlate.has_dynamic_resolvers
|
|
3623
|
+
breaker: this._breaker
|
|
3595
3624
|
},
|
|
3596
3625
|
options.settleDebounceMs ?? DEFAULT_SETTLE_DEBOUNCE_MS
|
|
3597
3626
|
);
|
|
@@ -3964,8 +3993,13 @@ var Act = class {
|
|
|
3964
3993
|
* Drain uses a dual-frontier strategy to balance processing of new streams (lagging)
|
|
3965
3994
|
* vs active streams (leading). The ratio adapts based on event pressure.
|
|
3966
3995
|
*
|
|
3967
|
-
* Call `correlate()` before `drain()
|
|
3968
|
-
*
|
|
3996
|
+
* Call `correlate()` before `drain()`. It is not only how dynamic targets
|
|
3997
|
+
* are discovered: a stream is claimable while `at < correlated_at`, and
|
|
3998
|
+
* `correlate` is the only component that raises that mark (#1487), so a
|
|
3999
|
+
* commit no correlate has seen is not drainable — including for static
|
|
4000
|
+
* targets, which were served by a probe of the event log before. For a
|
|
4001
|
+
* higher-level API that handles debouncing, correlation, and signaling
|
|
4002
|
+
* automatically, use {@link settle}.
|
|
3969
4003
|
*
|
|
3970
4004
|
* @param options - Drain configuration — see {@link DrainOptions} for fields
|
|
3971
4005
|
* (`streamLimit`, `eventLimit`, `leaseMillis`).
|
|
@@ -4515,6 +4549,26 @@ var Act = class {
|
|
|
4515
4549
|
* removed, so a later correlate can re-subscribe it (#1398). Restart
|
|
4516
4550
|
* targets keep their row, so only fully-retired streams are forgotten.
|
|
4517
4551
|
*/
|
|
4552
|
+
/**
|
|
4553
|
+
* Advance correlation until the read cursor reaches `until`, and report
|
|
4554
|
+
* where it landed (#1487). Used by the close cycle's safety probe, which
|
|
4555
|
+
* cannot judge a subscription's pending work over events correlate has
|
|
4556
|
+
* not resolved yet.
|
|
4557
|
+
*
|
|
4558
|
+
* Bounded on both ends: it stops as soon as a pass makes no progress (the
|
|
4559
|
+
* log has no more to give), and after {@link CLOSE_CATCH_UP_PASSES}
|
|
4560
|
+
* windows, so a close behind an enormous backlog degrades to skipping the
|
|
4561
|
+
* stream — the documented retryable outcome — instead of scanning the
|
|
4562
|
+
* whole log inside an operator call.
|
|
4563
|
+
*/
|
|
4564
|
+
async _catch_up_correlation(until) {
|
|
4565
|
+
for (let pass = 0; pass < CLOSE_CATCH_UP_PASSES && this._correlate.checkpoint < until; pass++) {
|
|
4566
|
+
const before = this._correlate.checkpoint;
|
|
4567
|
+
await this.correlate({ limit: CLOSE_CATCH_UP_LIMIT });
|
|
4568
|
+
if (this._correlate.checkpoint <= before) break;
|
|
4569
|
+
}
|
|
4570
|
+
return this._correlate.checkpoint;
|
|
4571
|
+
}
|
|
4518
4572
|
_forget_closed_subscriptions(result) {
|
|
4519
4573
|
const retired = [...result.truncated.entries()].filter(([, r]) => r.committed.name === TOMBSTONE_EVENT).map(([stream]) => stream);
|
|
4520
4574
|
if (retired.length) this._correlate.forget_subscribed(retired);
|
|
@@ -4526,6 +4580,7 @@ var Act = class {
|
|
|
4526
4580
|
const close_actor = { id: "$close", name: "close" };
|
|
4527
4581
|
const result = await run_close_cycle(targets, {
|
|
4528
4582
|
reactive_events_size: this._reactive_events.size,
|
|
4583
|
+
catch_up_correlation: (until) => this._catch_up_correlation(until),
|
|
4529
4584
|
event_to_state: this._event_to_state,
|
|
4530
4585
|
load: this._es.load,
|
|
4531
4586
|
tombstone: this._es.tombstone,
|