@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.cjs
CHANGED
|
@@ -1329,7 +1329,8 @@ var InMemoryStore = class {
|
|
|
1329
1329
|
leased_by: s.leased_by,
|
|
1330
1330
|
leased_until: s.leased_until,
|
|
1331
1331
|
lane: s.lane,
|
|
1332
|
-
deferred_at: s.deferred_at
|
|
1332
|
+
deferred_at: s.deferred_at,
|
|
1333
|
+
correlated_at: s.correlated_at
|
|
1333
1334
|
});
|
|
1334
1335
|
count++;
|
|
1335
1336
|
if (count >= limit) break;
|
|
@@ -2418,12 +2419,10 @@ function classify_registry(registry, states) {
|
|
|
2418
2419
|
const target_lanes = /* @__PURE__ */ new Map();
|
|
2419
2420
|
const reactive_events = /* @__PURE__ */ new Set();
|
|
2420
2421
|
const event_to_lanes = /* @__PURE__ */ new Map();
|
|
2421
|
-
let has_dynamic_resolvers = false;
|
|
2422
2422
|
for (const [name, register] of Object.entries(registry.events)) {
|
|
2423
2423
|
if (register.reactions.size > 0) reactive_events.add(name);
|
|
2424
2424
|
for (const reaction of register.reactions.values()) {
|
|
2425
2425
|
if (typeof reaction.resolver === "function") {
|
|
2426
|
-
has_dynamic_resolvers = true;
|
|
2427
2426
|
event_to_lanes.set(name, ALL_LANES);
|
|
2428
2427
|
} else {
|
|
2429
2428
|
const { target, source, priority = 0, lane } = reaction.resolver;
|
|
@@ -2459,7 +2458,6 @@ function classify_registry(registry, states) {
|
|
|
2459
2458
|
}
|
|
2460
2459
|
return {
|
|
2461
2460
|
static_targets: [...statics.values()],
|
|
2462
|
-
has_dynamic_resolvers,
|
|
2463
2461
|
reactive_events,
|
|
2464
2462
|
event_to_state,
|
|
2465
2463
|
event_to_lanes
|
|
@@ -2943,7 +2941,8 @@ async function run_close_cycle(targets, deps) {
|
|
|
2943
2941
|
stream_info,
|
|
2944
2942
|
deps.reactive_events_size,
|
|
2945
2943
|
skipped,
|
|
2946
|
-
deps.probe_page_size ?? SAFETY_PROBE_PAGE_SIZE
|
|
2944
|
+
deps.probe_page_size ?? SAFETY_PROBE_PAGE_SIZE,
|
|
2945
|
+
deps.catch_up_correlation
|
|
2947
2946
|
);
|
|
2948
2947
|
if (!safe.length) return { truncated: windowed_result, skipped };
|
|
2949
2948
|
const { guarded, guard_events } = await guard_with_tombstones(
|
|
@@ -3062,8 +3061,16 @@ async function scan_stream_heads(streams) {
|
|
|
3062
3061
|
}
|
|
3063
3062
|
return out;
|
|
3064
3063
|
}
|
|
3065
|
-
async function partition_by_safety(stream_info, reactive_events_size, skipped, page_size) {
|
|
3064
|
+
async function partition_by_safety(stream_info, reactive_events_size, skipped, page_size, catch_up_correlation) {
|
|
3066
3065
|
if (reactive_events_size === 0) return [...stream_info.keys()];
|
|
3066
|
+
let needed = -1;
|
|
3067
|
+
for (const info of stream_info.values())
|
|
3068
|
+
needed = Math.max(needed, info.max_id);
|
|
3069
|
+
const checkpoint = await catch_up_correlation(needed);
|
|
3070
|
+
const uncorrelated = /* @__PURE__ */ new Set();
|
|
3071
|
+
for (const [stream, info] of stream_info) {
|
|
3072
|
+
if (checkpoint < info.max_id) uncorrelated.add(stream);
|
|
3073
|
+
}
|
|
3067
3074
|
const pending_set = /* @__PURE__ */ new Set();
|
|
3068
3075
|
const source_regex = /* @__PURE__ */ new Map();
|
|
3069
3076
|
const get_regex = (source) => {
|
|
@@ -3082,6 +3089,8 @@ async function partition_by_safety(stream_info, reactive_events_size, skipped, p
|
|
|
3082
3089
|
(position) => {
|
|
3083
3090
|
last = position.stream;
|
|
3084
3091
|
const source_re = position.source ? get_regex(position.source) : void 0;
|
|
3092
|
+
const has_work = position.correlated_at === void 0 || position.at < position.correlated_at;
|
|
3093
|
+
if (!has_work) return;
|
|
3085
3094
|
for (const [stream, info] of stream_info) {
|
|
3086
3095
|
if ((!source_re || source_re.test(stream)) && position.at < info.max_id) {
|
|
3087
3096
|
pending_set.add(stream);
|
|
@@ -3095,7 +3104,8 @@ async function partition_by_safety(stream_info, reactive_events_size, skipped, p
|
|
|
3095
3104
|
}
|
|
3096
3105
|
const safe = [];
|
|
3097
3106
|
for (const [stream] of stream_info) {
|
|
3098
|
-
if (pending_set.has(stream)
|
|
3107
|
+
if (pending_set.has(stream) || uncorrelated.has(stream))
|
|
3108
|
+
skipped.push(stream);
|
|
3099
3109
|
else safe.push(stream);
|
|
3100
3110
|
}
|
|
3101
3111
|
return safe;
|
|
@@ -3185,21 +3195,24 @@ async function truncate_and_warm_cache(guarded, seed_states, guard_events, corre
|
|
|
3185
3195
|
|
|
3186
3196
|
// src/internal/correlate-cycle.ts
|
|
3187
3197
|
var DEFAULT_COLD_START_BACK_SCAN = 1e4;
|
|
3198
|
+
var PATTERN_CACHE_SIZE = 32;
|
|
3188
3199
|
var CorrelateCycle = class {
|
|
3189
3200
|
_checkpoint = -1;
|
|
3190
3201
|
_initialized = false;
|
|
3191
3202
|
/** In-flight init, memoized for single-flight and cleared on failure. */
|
|
3192
3203
|
_init_promise;
|
|
3193
3204
|
_timer = void 0;
|
|
3194
|
-
// target →
|
|
3195
|
-
//
|
|
3196
|
-
//
|
|
3197
|
-
//
|
|
3198
|
-
//
|
|
3205
|
+
// target → what it was last subscribed at. Every scan re-subscribes the
|
|
3206
|
+
// targets it resolved (that is how the work mark lands), so this no longer
|
|
3207
|
+
// decides *whether* a target is sent — it decides *what* is sent with it:
|
|
3208
|
+
// a resolution raises priority/lane only when it beats the recorded floor,
|
|
3209
|
+
// and otherwise re-sends the row's own values so the mark changes nothing
|
|
3210
|
+
// else. See {@link Subscription}.
|
|
3199
3211
|
_subscribed;
|
|
3212
|
+
/** Compiled pattern sources, bounded by {@link PATTERN_CACHE_SIZE}. */
|
|
3213
|
+
_patterns = new LruMap(PATTERN_CACHE_SIZE);
|
|
3200
3214
|
_registry;
|
|
3201
3215
|
_static_targets;
|
|
3202
|
-
_has_dynamic_resolvers;
|
|
3203
3216
|
_cd;
|
|
3204
3217
|
_on_init;
|
|
3205
3218
|
/**
|
|
@@ -3229,7 +3242,6 @@ var CorrelateCycle = class {
|
|
|
3229
3242
|
constructor({
|
|
3230
3243
|
registry,
|
|
3231
3244
|
static_targets,
|
|
3232
|
-
has_dynamic_resolvers,
|
|
3233
3245
|
cd,
|
|
3234
3246
|
max_subscribed_streams,
|
|
3235
3247
|
run_scoped,
|
|
@@ -3240,7 +3252,6 @@ var CorrelateCycle = class {
|
|
|
3240
3252
|
this._subscribed = new LruMap(max_subscribed_streams);
|
|
3241
3253
|
this._registry = registry;
|
|
3242
3254
|
this._static_targets = static_targets;
|
|
3243
|
-
this._has_dynamic_resolvers = has_dynamic_resolvers;
|
|
3244
3255
|
this._cd = cd;
|
|
3245
3256
|
this._on_init = on_init;
|
|
3246
3257
|
this._run_scoped = run_scoped;
|
|
@@ -3251,19 +3262,10 @@ var CorrelateCycle = class {
|
|
|
3251
3262
|
get checkpoint() {
|
|
3252
3263
|
return this._checkpoint;
|
|
3253
3264
|
}
|
|
3254
|
-
/**
|
|
3255
|
-
* Whether any reaction uses a dynamic resolver — i.e. whether `correlate`
|
|
3256
|
-
* performs a store scan rather than the static no-op early-return. The
|
|
3257
|
-
* settle loop reads this to avoid recording a fictitious circuit-breaker
|
|
3258
|
-
* success on a static app whose correlate never touches the store (#1329).
|
|
3259
|
-
*/
|
|
3260
|
-
get has_dynamic_resolvers() {
|
|
3261
|
-
return this._has_dynamic_resolvers;
|
|
3262
|
-
}
|
|
3263
3265
|
/**
|
|
3264
3266
|
* Initialize correlation state on first call.
|
|
3265
|
-
* - Reads max(at) from store,
|
|
3266
|
-
* `watermark - back_scan`
|
|
3267
|
+
* - Reads the durable correlate checkpoint (and max(at)) from the store,
|
|
3268
|
+
* flooring a first boot at `watermark - back_scan` so an event
|
|
3267
3269
|
* committed-but-not-correlated before a crash is re-scanned on
|
|
3268
3270
|
* restart instead of skipped (ACT-1207)
|
|
3269
3271
|
* - Subscribes static resolver targets (idempotent upsert)
|
|
@@ -3285,10 +3287,14 @@ var CorrelateCycle = class {
|
|
|
3285
3287
|
const { watermark, correlated_at } = await store2().subscribe([
|
|
3286
3288
|
...this._static_targets
|
|
3287
3289
|
]);
|
|
3288
|
-
this._checkpoint =
|
|
3290
|
+
this._checkpoint = correlated_at >= 0 ? correlated_at : Math.max(-1, watermark - this._cold_start_back_scan);
|
|
3289
3291
|
this._on_init?.();
|
|
3290
|
-
for (const { stream } of this._static_targets) {
|
|
3291
|
-
this._subscribed.set(stream,
|
|
3292
|
+
for (const { stream, priority = 0, lane } of this._static_targets) {
|
|
3293
|
+
this._subscribed.set(stream, {
|
|
3294
|
+
floor: Number.POSITIVE_INFINITY,
|
|
3295
|
+
priority,
|
|
3296
|
+
lane
|
|
3297
|
+
});
|
|
3292
3298
|
}
|
|
3293
3299
|
await this._on_init_async?.();
|
|
3294
3300
|
}
|
|
@@ -3313,14 +3319,34 @@ var CorrelateCycle = class {
|
|
|
3313
3319
|
}
|
|
3314
3320
|
}
|
|
3315
3321
|
/**
|
|
3316
|
-
*
|
|
3317
|
-
*
|
|
3318
|
-
*
|
|
3322
|
+
* Would an event from `stream` be fetched for a target subscribed with
|
|
3323
|
+
* `source`? The subscription's source is the filter `fetch` queries with
|
|
3324
|
+
* — literal names by equality, patterns compiled as a `RegExp` — so an
|
|
3325
|
+
* event outside it is not work for that target and must not mark it.
|
|
3326
|
+
* No source means the target consumes every stream.
|
|
3327
|
+
*/
|
|
3328
|
+
_in_fetch_window(source, stream) {
|
|
3329
|
+
if (source === void 0 || source === stream) return true;
|
|
3330
|
+
if (is_literal_source(source)) return false;
|
|
3331
|
+
let pattern = this._patterns.get(source);
|
|
3332
|
+
if (!pattern) {
|
|
3333
|
+
pattern = new RegExp(source);
|
|
3334
|
+
this._patterns.set(source, pattern);
|
|
3335
|
+
}
|
|
3336
|
+
return pattern.test(stream);
|
|
3337
|
+
}
|
|
3338
|
+
/**
|
|
3339
|
+
* Scan the events past the checkpoint, resolve each to its target
|
|
3340
|
+
* streams, and record what it found through `cd.subscribe` — new dynamic
|
|
3341
|
+
* targets get registered, and every target an event resolved to gets its
|
|
3342
|
+
* **work mark** raised to that event's id (#1487).
|
|
3343
|
+
*
|
|
3344
|
+
* Both resolver kinds are walked. A static target is already subscribed
|
|
3345
|
+
* at init, but marking it is what makes it claimable without probing the
|
|
3346
|
+
* event log, so the scan runs for every app.
|
|
3319
3347
|
*/
|
|
3320
3348
|
async correlate(query = { after: -1, limit: 10 }) {
|
|
3321
3349
|
await this.init();
|
|
3322
|
-
if (!this._has_dynamic_resolvers)
|
|
3323
|
-
return { subscribed: 0, last_id: this._checkpoint };
|
|
3324
3350
|
const after = Math.max(this._checkpoint, query.after || -1);
|
|
3325
3351
|
const correlated = /* @__PURE__ */ new Map();
|
|
3326
3352
|
let last_id = after;
|
|
@@ -3330,47 +3356,53 @@ var CorrelateCycle = class {
|
|
|
3330
3356
|
const register = this._registry.events[event.name];
|
|
3331
3357
|
if (register) {
|
|
3332
3358
|
for (const reaction of register.reactions.values()) {
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
entry.
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
event
|
|
3351
|
-
});
|
|
3352
|
-
correlated.set(resolved.target, entry);
|
|
3359
|
+
const resolved = typeof reaction.resolver === "function" ? reaction.resolver(event) : reaction.resolver;
|
|
3360
|
+
if (!resolved) continue;
|
|
3361
|
+
const recorded = this._subscribed.get(resolved.target);
|
|
3362
|
+
const priority = resolved.priority ?? 0;
|
|
3363
|
+
const upgraded = !recorded || priority > recorded.floor;
|
|
3364
|
+
const carried = upgraded ? { priority, lane: resolved.lane } : { priority: recorded.priority, lane: recorded.lane };
|
|
3365
|
+
const entry = correlated.get(resolved.target) || {
|
|
3366
|
+
source: resolved.source,
|
|
3367
|
+
priority: carried.priority,
|
|
3368
|
+
lane: carried.lane,
|
|
3369
|
+
upgraded,
|
|
3370
|
+
correlated_at: void 0
|
|
3371
|
+
};
|
|
3372
|
+
if (carried.priority > entry.priority) {
|
|
3373
|
+
entry.priority = carried.priority;
|
|
3374
|
+
entry.lane = carried.lane;
|
|
3375
|
+
entry.upgraded = upgraded;
|
|
3353
3376
|
}
|
|
3377
|
+
if (this._in_fetch_window(resolved.source, event.stream))
|
|
3378
|
+
entry.correlated_at = event.id;
|
|
3379
|
+
correlated.set(resolved.target, entry);
|
|
3354
3380
|
}
|
|
3355
3381
|
}
|
|
3356
3382
|
},
|
|
3357
3383
|
{ ...query, after }
|
|
3358
3384
|
);
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3385
|
+
const streams = [];
|
|
3386
|
+
for (const [stream, entry] of correlated) {
|
|
3387
|
+
if (entry.upgraded || entry.correlated_at !== void 0)
|
|
3388
|
+
streams.push({
|
|
3362
3389
|
stream,
|
|
3363
|
-
source,
|
|
3364
|
-
priority,
|
|
3365
|
-
lane
|
|
3366
|
-
|
|
3367
|
-
|
|
3390
|
+
source: entry.source,
|
|
3391
|
+
priority: entry.priority,
|
|
3392
|
+
lane: entry.lane,
|
|
3393
|
+
correlated_at: entry.correlated_at
|
|
3394
|
+
});
|
|
3395
|
+
}
|
|
3396
|
+
if (streams.length) {
|
|
3368
3397
|
const { subscribed } = await this._cd.subscribe(streams, last_id);
|
|
3369
3398
|
this._checkpoint = last_id;
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
this._subscribed.set(stream,
|
|
3373
|
-
|
|
3399
|
+
for (const { stream, priority, lane } of streams) {
|
|
3400
|
+
if (correlated.get(stream)?.upgraded)
|
|
3401
|
+
this._subscribed.set(stream, {
|
|
3402
|
+
floor: priority,
|
|
3403
|
+
priority,
|
|
3404
|
+
lane
|
|
3405
|
+
});
|
|
3374
3406
|
}
|
|
3375
3407
|
return { subscribed, last_id };
|
|
3376
3408
|
}
|
|
@@ -4678,7 +4710,7 @@ var SettleLoop = class {
|
|
|
4678
4710
|
...correlate_query,
|
|
4679
4711
|
after: after_before
|
|
4680
4712
|
});
|
|
4681
|
-
|
|
4713
|
+
this._deps.breaker.passed();
|
|
4682
4714
|
const drain = await this._deps.drain(drain_options);
|
|
4683
4715
|
settled_drain = settled_drain ? {
|
|
4684
4716
|
fetched: [...settled_drain.fetched, ...drain.fetched],
|
|
@@ -4724,6 +4756,8 @@ var SettleLoop = class {
|
|
|
4724
4756
|
|
|
4725
4757
|
// src/act.ts
|
|
4726
4758
|
var DEFAULT_MAX_SUBSCRIBED_STREAMS = 1e3;
|
|
4759
|
+
var CLOSE_CATCH_UP_LIMIT = 1e3;
|
|
4760
|
+
var CLOSE_CATCH_UP_PASSES = 20;
|
|
4727
4761
|
var DEFAULT_SETTLE_DEBOUNCE_MS = 10;
|
|
4728
4762
|
function validate_only_lanes(options, lanes) {
|
|
4729
4763
|
if (!options.onlyLanes || options.onlyLanes.length === 0) return;
|
|
@@ -5039,6 +5073,7 @@ var Act = class {
|
|
|
5039
5073
|
const close_actor = { id: "$close", name: "close" };
|
|
5040
5074
|
const result = await run_close_cycle(targets, {
|
|
5041
5075
|
reactive_events_size: this._reactive_events.size,
|
|
5076
|
+
catch_up_correlation: (until) => this._catch_up_correlation(until),
|
|
5042
5077
|
event_to_state: this._event_to_state,
|
|
5043
5078
|
load: this._es.load,
|
|
5044
5079
|
tombstone: this._es.tombstone,
|
|
@@ -5125,7 +5160,6 @@ var Act = class {
|
|
|
5125
5160
|
return new CorrelateCycle({
|
|
5126
5161
|
registry: this.registry,
|
|
5127
5162
|
static_targets: classification.static_targets,
|
|
5128
|
-
has_dynamic_resolvers: classification.has_dynamic_resolvers,
|
|
5129
5163
|
cd: this._cd,
|
|
5130
5164
|
max_subscribed_streams: options.maxSubscribedStreams ?? DEFAULT_MAX_SUBSCRIBED_STREAMS,
|
|
5131
5165
|
on_init: () => {
|
|
@@ -5176,11 +5210,7 @@ var Act = class {
|
|
|
5176
5210
|
correlate: (q) => this.correlate(q),
|
|
5177
5211
|
drain: (o) => this.drain(o),
|
|
5178
5212
|
on_settled: (drain) => this.emit("settled", drain),
|
|
5179
|
-
breaker: this._breaker
|
|
5180
|
-
// Static-reaction apps' correlate is a no-op (no store call), so a
|
|
5181
|
-
// settle pass carries no store-health signal — don't let it record a
|
|
5182
|
-
// breaker success (#1329).
|
|
5183
|
-
correlate_probes_store: this._correlate.has_dynamic_resolvers
|
|
5213
|
+
breaker: this._breaker
|
|
5184
5214
|
},
|
|
5185
5215
|
options.settleDebounceMs ?? DEFAULT_SETTLE_DEBOUNCE_MS
|
|
5186
5216
|
);
|
|
@@ -5553,8 +5583,13 @@ var Act = class {
|
|
|
5553
5583
|
* Drain uses a dual-frontier strategy to balance processing of new streams (lagging)
|
|
5554
5584
|
* vs active streams (leading). The ratio adapts based on event pressure.
|
|
5555
5585
|
*
|
|
5556
|
-
* Call `correlate()` before `drain()
|
|
5557
|
-
*
|
|
5586
|
+
* Call `correlate()` before `drain()`. It is not only how dynamic targets
|
|
5587
|
+
* are discovered: a stream is claimable while `at < correlated_at`, and
|
|
5588
|
+
* `correlate` is the only component that raises that mark (#1487), so a
|
|
5589
|
+
* commit no correlate has seen is not drainable — including for static
|
|
5590
|
+
* targets, which were served by a probe of the event log before. For a
|
|
5591
|
+
* higher-level API that handles debouncing, correlation, and signaling
|
|
5592
|
+
* automatically, use {@link settle}.
|
|
5558
5593
|
*
|
|
5559
5594
|
* @param options - Drain configuration — see {@link DrainOptions} for fields
|
|
5560
5595
|
* (`streamLimit`, `eventLimit`, `leaseMillis`).
|
|
@@ -6104,6 +6139,26 @@ var Act = class {
|
|
|
6104
6139
|
* removed, so a later correlate can re-subscribe it (#1398). Restart
|
|
6105
6140
|
* targets keep their row, so only fully-retired streams are forgotten.
|
|
6106
6141
|
*/
|
|
6142
|
+
/**
|
|
6143
|
+
* Advance correlation until the read cursor reaches `until`, and report
|
|
6144
|
+
* where it landed (#1487). Used by the close cycle's safety probe, which
|
|
6145
|
+
* cannot judge a subscription's pending work over events correlate has
|
|
6146
|
+
* not resolved yet.
|
|
6147
|
+
*
|
|
6148
|
+
* Bounded on both ends: it stops as soon as a pass makes no progress (the
|
|
6149
|
+
* log has no more to give), and after {@link CLOSE_CATCH_UP_PASSES}
|
|
6150
|
+
* windows, so a close behind an enormous backlog degrades to skipping the
|
|
6151
|
+
* stream — the documented retryable outcome — instead of scanning the
|
|
6152
|
+
* whole log inside an operator call.
|
|
6153
|
+
*/
|
|
6154
|
+
async _catch_up_correlation(until) {
|
|
6155
|
+
for (let pass = 0; pass < CLOSE_CATCH_UP_PASSES && this._correlate.checkpoint < until; pass++) {
|
|
6156
|
+
const before = this._correlate.checkpoint;
|
|
6157
|
+
await this.correlate({ limit: CLOSE_CATCH_UP_LIMIT });
|
|
6158
|
+
if (this._correlate.checkpoint <= before) break;
|
|
6159
|
+
}
|
|
6160
|
+
return this._correlate.checkpoint;
|
|
6161
|
+
}
|
|
6107
6162
|
_forget_closed_subscriptions(result) {
|
|
6108
6163
|
const retired = [...result.truncated.entries()].filter(([, r]) => r.committed.name === TOMBSTONE_EVENT).map(([stream]) => stream);
|
|
6109
6164
|
if (retired.length) this._correlate.forget_subscribed(retired);
|
|
@@ -6115,6 +6170,7 @@ var Act = class {
|
|
|
6115
6170
|
const close_actor = { id: "$close", name: "close" };
|
|
6116
6171
|
const result = await run_close_cycle(targets, {
|
|
6117
6172
|
reactive_events_size: this._reactive_events.size,
|
|
6173
|
+
catch_up_correlation: (until) => this._catch_up_correlation(until),
|
|
6118
6174
|
event_to_state: this._event_to_state,
|
|
6119
6175
|
load: this._es.load,
|
|
6120
6176
|
tombstone: this._es.tombstone,
|