@rotorsoft/act 1.33.2 → 1.33.4

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
@@ -1370,13 +1370,14 @@ var CorrelateCycle = class {
1370
1370
  });
1371
1371
  }
1372
1372
  if (streams.length) {
1373
+ const held = lease && this._lease_until > 0;
1373
1374
  const renewed_at = Date.now();
1374
1375
  const { subscribed, correlating } = await this._cd.subscribe(
1375
1376
  streams,
1376
1377
  last_id,
1377
- lease ? { key: this._key, by: this._by, millis: CORRELATION_LEASE_MS } : void 0
1378
+ held ? { key: this._key, by: this._by, millis: CORRELATION_LEASE_MS } : void 0
1378
1379
  );
1379
- if (lease && correlating !== false)
1380
+ if (held && correlating !== false)
1380
1381
  this._lease_until = renewed_at + CORRELATION_LEASE_MS;
1381
1382
  const marked = streams.filter(
1382
1383
  (entry) => entry.correlated_at !== void 0
@@ -2365,7 +2366,7 @@ var DrainController = class {
2365
2366
  _defer = new DeferTimer(() => {
2366
2367
  this._armed = true;
2367
2368
  void this._deps.run_scoped(async () => {
2368
- while (!this._stopped && (await this.drain()).leased.length > 0) ;
2369
+ while ((await this.drain()).leased.length > 0) ;
2369
2370
  });
2370
2371
  });
2371
2372
  _worker;
@@ -2421,7 +2422,7 @@ var DrainController = class {
2421
2422
  this._defer.stop();
2422
2423
  }
2423
2424
  async drain(options = {}) {
2424
- if (!this._armed) return EMPTY_DRAIN;
2425
+ if (!this._armed || this._stopped) return EMPTY_DRAIN;
2425
2426
  if (this._locked) return EMPTY_DRAIN;
2426
2427
  const d = this._deps.defaults ?? {};
2427
2428
  const streamLimit = d.streamLimit ?? options.streamLimit ?? DEFAULT_STREAM_LIMIT;
@@ -2785,10 +2786,9 @@ function build_handle_batch(logger) {
2785
2786
  // src/internal/settle.ts
2786
2787
  var SettleLoop = class {
2787
2788
  _timer = void 0;
2788
- _running = false;
2789
2789
  /**
2790
- * Resolves when the cycle in flight finishes, so shutdown can wait for
2791
- * it (`stop()` cancels scheduling only). Never rejects.
2790
+ * The cycle in flight, set while one runs. Shutdown waits for it
2791
+ * (`stop()` cancels scheduling only). Never rejects.
2792
2792
  */
2793
2793
  _inflight;
2794
2794
  /** A wake-up arrived while a cycle ran: run one more pass after it. */
@@ -2820,7 +2820,7 @@ var SettleLoop = class {
2820
2820
  schedule(options) {
2821
2821
  if (this._stopped) return;
2822
2822
  if (options) this._next = options;
2823
- if (this._running) {
2823
+ if (this._inflight) {
2824
2824
  this._pending = true;
2825
2825
  return;
2826
2826
  }
@@ -2840,12 +2840,7 @@ var SettleLoop = class {
2840
2840
  ...drain_options
2841
2841
  } = this._next ?? {};
2842
2842
  this._next = void 0;
2843
- this._running = true;
2844
- let settle_done;
2845
- this._inflight = new Promise((done) => {
2846
- settle_done = done;
2847
- });
2848
- (async () => {
2843
+ this._inflight = (async () => {
2849
2844
  await this._deps.init();
2850
2845
  let settled_drain;
2851
2846
  for (let i = 0; i < maxPasses && !this._stopped; i++) {
@@ -2869,9 +2864,7 @@ var SettleLoop = class {
2869
2864
  })().catch((err) => {
2870
2865
  this._deps.breaker.failed(Date.now(), err);
2871
2866
  }).finally(() => {
2872
- this._running = false;
2873
2867
  this._inflight = void 0;
2874
- settle_done();
2875
2868
  if (this._pending) {
2876
2869
  this._pending = false;
2877
2870
  this.schedule(this._next);
@@ -3178,7 +3171,9 @@ var Act = class {
3178
3171
  { ...q, limit: q.limit ?? this._poll_limit ?? 100 },
3179
3172
  true
3180
3173
  ),
3181
- drain: (o) => this.drain(o),
3174
+ // `settle()` validated the options, and `_schedule` skips writer-only
3175
+ // instances, so the loop drains through the internal path.
3176
+ drain: (o) => this._scoped(() => this._drain_all(o)),
3182
3177
  on_settled: (drain) => this.emit("settled", drain),
3183
3178
  breaker: this._breaker
3184
3179
  },
@@ -3204,11 +3199,11 @@ var Act = class {
3204
3199
  resolveShutdownConfig(options);
3205
3200
  this._shutdown_promise = (async () => {
3206
3201
  this.stop_correlations();
3207
- const disposer = await this._notify_disposer;
3208
- if (disposer) await disposer();
3209
3202
  this._settle.stop(true);
3210
3203
  this._breaker.stop();
3211
3204
  for (const c of this._drain_controllers.values()) c.stop();
3205
+ const disposer = await this._notify_disposer;
3206
+ if (disposer) await disposer();
3212
3207
  await this._await_inflight(options?.graceMs);
3213
3208
  await this._scoped(() => this._correlate.release_correlation());
3214
3209
  this._emitter.removeAllListeners();
@@ -3256,12 +3251,7 @@ var Act = class {
3256
3251
  return await s.notify((notification) => {
3257
3252
  try {
3258
3253
  this.emit("notified", notification);
3259
- if (this._drain) {
3260
- const armed = this._arm_for_event_names(
3261
- notification.events.map((e) => e.name)
3262
- );
3263
- this._settle_armed(armed);
3264
- }
3254
+ this._wake(notification.events.map((e) => e.name));
3265
3255
  } catch (err) {
3266
3256
  this._logger.error(err, "notified handler threw");
3267
3257
  }
@@ -3319,10 +3309,7 @@ var Act = class {
3319
3309
  payload,
3320
3310
  do_options
3321
3311
  );
3322
- const armed = this._arm_for_event_names(
3323
- snapshots.map((s) => s.event.name)
3324
- );
3325
- this._settle_armed(armed);
3312
+ this._wake(snapshots.map((s) => s.event.name));
3326
3313
  this.emit("committed", snapshots);
3327
3314
  return snapshots;
3328
3315
  });
@@ -3469,17 +3456,21 @@ var Act = class {
3469
3456
  return { fetched: [], leased: [], acked: [], blocked: [] };
3470
3457
  return this._scoped(() => this._drain_all(options));
3471
3458
  }
3459
+ /** Arms correlate and every lane; false on an app with no reactions. */
3472
3460
  _arm_all() {
3473
- if (!this._reactive) return;
3461
+ if (!this._reactive) return false;
3474
3462
  this._correlate.arm();
3475
3463
  for (const c of this._drain_controllers.values()) c.arm();
3464
+ return true;
3476
3465
  }
3477
3466
  /**
3478
- * Settles what a change armed (a commit, a reset, an unblock, a restore,
3479
- * a notification from another process), unless the app walks the
3480
- * pipeline itself (`autoSettle: false`).
3467
+ * Wakes what a change freed (a commit, a reset, an unblock, a restore,
3468
+ * a notification from another process): arms the lanes these events
3469
+ * react on, or every lane without names, and settles them unless the app
3470
+ * walks the pipeline itself (`autoSettle: false`).
3481
3471
  */
3482
- _settle_armed(armed) {
3472
+ _wake(names) {
3473
+ const armed = names ? this._arm_for_event_names(names) : this._arm_all();
3483
3474
  if (armed && this._auto_settle) this._schedule();
3484
3475
  }
3485
3476
  /** Schedules a settle pass; writer-only instances (`drain: false`) skip it. */
@@ -3647,8 +3638,7 @@ var Act = class {
3647
3638
  for (const handler of this._batch_handlers.values())
3648
3639
  handler[FOLD_RESET]?.();
3649
3640
  if (count > 0) {
3650
- this._arm_all();
3651
- this._settle_armed(this._reactive);
3641
+ this._wake();
3652
3642
  }
3653
3643
  return count;
3654
3644
  });
@@ -3682,8 +3672,7 @@ var Act = class {
3682
3672
  return this._scoped(async () => {
3683
3673
  const count = await store().unblock(input);
3684
3674
  if (count > 0) {
3685
- this._arm_all();
3686
- this._settle_armed(this._reactive);
3675
+ this._wake();
3687
3676
  }
3688
3677
  return count;
3689
3678
  });
@@ -3745,8 +3734,7 @@ var Act = class {
3745
3734
  });
3746
3735
  if (!sink) {
3747
3736
  this._correlate.restart();
3748
- this._arm_all();
3749
- this._settle_armed(this._reactive);
3737
+ this._wake();
3750
3738
  }
3751
3739
  return { kept, migrated, dropped, duration_ms: Date.now() - started };
3752
3740
  });