@rotorsoft/act 1.33.8 → 1.33.10

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
@@ -40,7 +40,7 @@ import {
40
40
  sleep,
41
41
  store,
42
42
  validate
43
- } from "./chunk-NNTF627K.js";
43
+ } from "./chunk-OCJXGHN6.js";
44
44
  import {
45
45
  ActorSchema,
46
46
  CausationEventSchema,
@@ -1162,8 +1162,14 @@ var CorrelateCycle = class {
1162
1162
  _key;
1163
1163
  /** Local expiry of the held lease (0 = none); stale only costs a duplicate scan. */
1164
1164
  _lease_until = 0;
1165
- /** Raised by a commit or notification, lowered by a short page. Starts armed. */
1166
- _armed = true;
1165
+ /**
1166
+ * Armed while `_raised` (bumped by a commit or notification) is ahead of
1167
+ * `_lowered` (the raise count the last short page saw). Starts armed.
1168
+ */
1169
+ _raised = 1;
1170
+ _lowered = 0;
1171
+ /** Counts releases, so a lease reply that lands after one is dropped. */
1172
+ _releases = 0;
1167
1173
  _init_promise;
1168
1174
  // Bounded by `maxSubscribedStreams`; static records live apart so eviction
1169
1175
  // never drops their +Infinity floor.
@@ -1199,7 +1205,7 @@ var CorrelateCycle = class {
1199
1205
  }
1200
1206
  /** A commit (local or remote) may have produced uncorrelated events. */
1201
1207
  arm() {
1202
- this._armed = true;
1208
+ this._raised++;
1203
1209
  }
1204
1210
  async init() {
1205
1211
  if (this._initialized) return;
@@ -1233,7 +1239,7 @@ var CorrelateCycle = class {
1233
1239
  this._checkpoint = -1;
1234
1240
  this._dynamic_subscriptions.clear();
1235
1241
  this._static_subscriptions.clear();
1236
- this._armed = true;
1242
+ this._raised++;
1237
1243
  }
1238
1244
  /** Forget dynamic targets whose rows a full close deleted, so they re-subscribe. */
1239
1245
  forget_subscribed(streams) {
@@ -1253,22 +1259,26 @@ var CorrelateCycle = class {
1253
1259
  /** Scan past the checkpoint, subscribe new targets and raise their work marks. */
1254
1260
  async correlate(query = { after: -1, limit: 10 }, lease = false) {
1255
1261
  await this.init();
1256
- if (!this._armed)
1262
+ if (this._raised === this._lowered)
1257
1263
  return {
1258
1264
  subscribed: 0,
1259
1265
  last_id: this._checkpoint,
1260
1266
  marked: 0,
1261
1267
  scanned: false
1262
1268
  };
1269
+ const raised = this._raised;
1263
1270
  const now = Date.now();
1264
1271
  if (lease && now >= this._lease_until - CORRELATION_LEASE_MS / 2) {
1272
+ const releases = this._releases;
1265
1273
  const { correlating } = await this._cd.subscribe([], void 0, {
1266
1274
  key: this._key,
1267
1275
  by: this._by,
1268
1276
  millis: CORRELATION_LEASE_MS
1269
1277
  });
1270
- this._lease_until = correlating ? now + CORRELATION_LEASE_MS : 0;
1271
- if (correlating === false)
1278
+ const released = this._releases !== releases;
1279
+ if (!released)
1280
+ this._lease_until = correlating ? now + CORRELATION_LEASE_MS : 0;
1281
+ if (correlating === false || released)
1272
1282
  return {
1273
1283
  subscribed: 0,
1274
1284
  last_id: this._checkpoint,
@@ -1389,7 +1399,7 @@ var CorrelateCycle = class {
1389
1399
  return { subscribed, last_id, marked, scanned: true };
1390
1400
  }
1391
1401
  this._checkpoint = last_id;
1392
- this._armed = stopped || found === query.limit;
1402
+ if (!stopped && found !== query.limit) this._lowered = raised;
1393
1403
  return { subscribed: 0, last_id, marked: 0, scanned: true };
1394
1404
  }
1395
1405
  /**
@@ -1435,6 +1445,7 @@ var CorrelateCycle = class {
1435
1445
  async release_correlation() {
1436
1446
  try {
1437
1447
  this._lease_until = 0;
1448
+ this._releases++;
1438
1449
  await this._cd.subscribe([], void 0, {
1439
1450
  key: this._key,
1440
1451
  by: this._by,
@@ -2348,7 +2359,13 @@ var EMPTY_DRAIN = {
2348
2359
  };
2349
2360
  var RETRY = "";
2350
2361
  var DrainController = class {
2351
- _armed = false;
2362
+ /**
2363
+ * Armed while `_raised` is ahead of `_lowered` (the raise count the last
2364
+ * empty claim saw), so a claim never lowers over a raise that landed
2365
+ * during it.
2366
+ */
2367
+ _raised = 0;
2368
+ _lowered = 0;
2352
2369
  _ratio = 0.5;
2353
2370
  /**
2354
2371
  * Local wake at the earliest parked (backoff or defer) visit, or at the
@@ -2358,7 +2375,7 @@ var DrainController = class {
2358
2375
  * stays until handled or until a later pass claims nothing.
2359
2376
  */
2360
2377
  _defer = new DeferTimer(() => {
2361
- this._armed = true;
2378
+ this.arm();
2362
2379
  void this._deps.run_scoped(async () => {
2363
2380
  while ((await this.drain()).leased.length > 0) ;
2364
2381
  });
@@ -2374,7 +2391,7 @@ var DrainController = class {
2374
2391
  this._deps = deps;
2375
2392
  }
2376
2393
  arm() {
2377
- this._armed = true;
2394
+ this._raised++;
2378
2395
  }
2379
2396
  /** Cold start: re-seed a persisted `deferred_at` into the local wake. */
2380
2397
  seed_defer(stream, at) {
@@ -2382,7 +2399,7 @@ var DrainController = class {
2382
2399
  this._defer.schedule();
2383
2400
  }
2384
2401
  get armed() {
2385
- return this._armed;
2402
+ return this._raised !== this._lowered;
2386
2403
  }
2387
2404
  get inflight() {
2388
2405
  return this._inflight;
@@ -2399,7 +2416,7 @@ var DrainController = class {
2399
2416
  if (this._worker || this._stopped) return;
2400
2417
  const run = this._deps.run_scoped;
2401
2418
  const tick = async () => {
2402
- if (this._armed) await run(() => this.drain());
2419
+ if (this.armed) await run(() => this.drain());
2403
2420
  if (this._stopped) return;
2404
2421
  this._worker = setTimeout(tick, cycleMs);
2405
2422
  this._worker.unref();
@@ -2416,7 +2433,7 @@ var DrainController = class {
2416
2433
  this._defer.stop();
2417
2434
  }
2418
2435
  async drain(options = {}) {
2419
- if (!this._armed || this._stopped || this._inflight)
2436
+ if (!this.armed || this._stopped || this._inflight)
2420
2437
  return EMPTY_DRAIN;
2421
2438
  const d = this._deps.defaults ?? {};
2422
2439
  const streamLimit = d.streamLimit ?? options.streamLimit ?? DEFAULT_STREAM_LIMIT;
@@ -2431,6 +2448,7 @@ var DrainController = class {
2431
2448
  const lagging = Math.ceil(streamLimit * this._ratio);
2432
2449
  const leading = streamLimit - lagging;
2433
2450
  const started = Date.now();
2451
+ const raised = this._raised;
2434
2452
  const cycle = await run_drain_cycle(this._deps, {
2435
2453
  lagging,
2436
2454
  leading,
@@ -2442,7 +2460,7 @@ var DrainController = class {
2442
2460
  if (!cycle) {
2443
2461
  this._defer.prune(started);
2444
2462
  this._deps.breaker.passed();
2445
- this._armed = false;
2463
+ this._lowered = raised;
2446
2464
  return EMPTY_DRAIN;
2447
2465
  }
2448
2466
  const { leased, fetched, handled, acked, blocked, closeable } = cycle;