@rotorsoft/act 0.6.2 → 0.6.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
@@ -215,53 +215,54 @@ var InMemoryStream = class {
215
215
  }
216
216
  /**
217
217
  * Attempt to lease this stream for processing.
218
- * @param at - The end-of-lease watermark.
219
- * @param by - The lease holder.
218
+ * @param lease - The lease request.
220
219
  * @param millis - Lease duration in milliseconds.
221
220
  * @returns The granted lease or undefined if blocked.
222
221
  */
223
- lease(at, by, millis) {
222
+ lease(lease, millis) {
224
223
  if (this.is_avaliable) {
225
224
  if (millis > 0) {
226
- this._leased_by = by;
225
+ this._leased_by = lease.by;
227
226
  this._leased_until = new Date(Date.now() + millis);
228
227
  this._retry = this._retry + 1;
229
228
  }
230
229
  return {
231
230
  stream: this.stream,
232
231
  source: this.source,
233
- at,
234
- by,
235
- retry: this._retry
232
+ at: lease.at,
233
+ by: lease.by,
234
+ retry: this._retry,
235
+ lagging: lease.lagging
236
236
  };
237
237
  }
238
238
  }
239
239
  /**
240
240
  * Acknowledge completion of processing for this stream.
241
- * @param at - Last processed watermark.
242
- * @param by - Lease holder that processed the watermark.
241
+ * @param lease - The lease request.
243
242
  */
244
- ack(at, by) {
245
- if (this._leased_by === by) {
243
+ ack(lease) {
244
+ if (this._leased_by === lease.by) {
246
245
  this._leased_by = void 0;
247
246
  this._leased_until = void 0;
248
- this._at = at;
247
+ this._at = lease.at;
249
248
  this._retry = -1;
250
249
  return {
251
250
  stream: this.stream,
252
251
  source: this.source,
253
252
  at: this._at,
254
- by,
255
- retry: this._retry
253
+ by: lease.by,
254
+ retry: this._retry,
255
+ lagging: lease.lagging
256
256
  };
257
257
  }
258
258
  }
259
259
  /**
260
260
  * Block a stream for processing after failing to process and reaching max retries with blocking enabled.
261
+ * @param lease - The lease request.
261
262
  * @param error Blocked error message.
262
263
  */
263
- block(by, error) {
264
- if (this._leased_by === by) {
264
+ block(lease, error) {
265
+ if (this._leased_by === lease.by) {
265
266
  this._blocked = true;
266
267
  this._error = error;
267
268
  return {
@@ -270,7 +271,8 @@ var InMemoryStream = class {
270
271
  at: this._at,
271
272
  by: this._leased_by,
272
273
  retry: this._retry,
273
- error: this._error
274
+ error: this._error,
275
+ lagging: lease.lagging
274
276
  };
275
277
  }
276
278
  }
@@ -394,8 +396,18 @@ var InMemoryStore = class {
394
396
  */
395
397
  async poll(lagging, leading) {
396
398
  await sleep();
397
- const a = [...this._streams.values()].filter((s) => s.is_avaliable).sort((a2, b2) => a2.at - b2.at).slice(0, lagging).map(({ stream, source, at }) => ({ stream, source, at }));
398
- const b = [...this._streams.values()].filter((s) => s.is_avaliable).sort((a2, b2) => b2.at - a2.at).slice(0, leading).map(({ stream, source, at }) => ({ stream, source, at }));
399
+ const a = [...this._streams.values()].filter((s) => s.is_avaliable).sort((a2, b2) => a2.at - b2.at).slice(0, lagging).map(({ stream, source, at }) => ({
400
+ stream,
401
+ source,
402
+ at,
403
+ lagging: true
404
+ }));
405
+ const b = [...this._streams.values()].filter((s) => s.is_avaliable).sort((a2, b2) => b2.at - a2.at).slice(0, leading).map(({ stream, source, at }) => ({
406
+ stream,
407
+ source,
408
+ at,
409
+ lagging: false
410
+ }));
399
411
  return [...a, ...b];
400
412
  }
401
413
  /**
@@ -410,7 +422,7 @@ var InMemoryStore = class {
410
422
  if (!this._streams.has(l.stream)) {
411
423
  this._streams.set(l.stream, new InMemoryStream(l.stream, l.source));
412
424
  }
413
- return this._streams.get(l.stream)?.lease(l.at, l.by, millis);
425
+ return this._streams.get(l.stream)?.lease(l, millis);
414
426
  }).filter((l) => !!l);
415
427
  }
416
428
  /**
@@ -419,7 +431,7 @@ var InMemoryStore = class {
419
431
  */
420
432
  async ack(leases) {
421
433
  await sleep();
422
- return leases.map((l) => this._streams.get(l.stream)?.ack(l.at, l.by)).filter((l) => !!l);
434
+ return leases.map((l) => this._streams.get(l.stream)?.ack(l)).filter((l) => !!l);
423
435
  }
424
436
  /**
425
437
  * Block a stream for processing after failing to process and reaching max retries with blocking enabled.
@@ -428,7 +440,7 @@ var InMemoryStore = class {
428
440
  */
429
441
  async block(leases) {
430
442
  await sleep();
431
- return leases.map((l) => this._streams.get(l.stream)?.block(l.by, l.error)).filter((l) => !!l);
443
+ return leases.map((l) => this._streams.get(l.stream)?.block(l, l.error)).filter((l) => !!l);
432
444
  }
433
445
  };
434
446
 
@@ -688,6 +700,7 @@ var Act = class {
688
700
  }
689
701
  _emitter = new EventEmitter();
690
702
  _drain_locked = false;
703
+ _drain_lag2lead_ratio = 0.5;
691
704
  _correlation_interval = void 0;
692
705
  emit(event, args) {
693
706
  return this._emitter.emit(event, args);
@@ -790,7 +803,7 @@ var Act = class {
790
803
  * @returns The lease with results
791
804
  */
792
805
  async handle(lease, payloads) {
793
- if (payloads.length === 0) return { lease, at: lease.at };
806
+ if (payloads.length === 0) return { lease, handled: 0, at: lease.at };
794
807
  const stream = lease.stream;
795
808
  let at = payloads.at(0).event.id, handled = 0;
796
809
  lease.retry > 0 && logger.warn(`Retrying ${stream}@${at} (${lease.retry}).`);
@@ -806,6 +819,7 @@ var Act = class {
806
819
  block && logger.error(`Blocking ${stream} after ${lease.retry} retries.`);
807
820
  return {
808
821
  lease,
822
+ handled,
809
823
  at,
810
824
  // only report error when nothing was handled
811
825
  error: handled === 0 ? error.message : void 0,
@@ -813,7 +827,7 @@ var Act = class {
813
827
  };
814
828
  }
815
829
  }
816
- return { lease, at };
830
+ return { lease, handled, at };
817
831
  }
818
832
  /**
819
833
  * Drains and processes events from the store, triggering reactions and updating state.
@@ -833,27 +847,27 @@ var Act = class {
833
847
  if (!this._drain_locked) {
834
848
  try {
835
849
  this._drain_locked = true;
836
- const lagging = Math.ceil(streamLimit * 2 / 3);
850
+ const lagging = Math.ceil(streamLimit * this._drain_lag2lead_ratio);
837
851
  const leading = streamLimit - lagging;
838
852
  const polled = await store().poll(lagging, leading);
839
853
  const fetched = await Promise.all(
840
- polled.map(async ({ stream, source, at }) => {
854
+ polled.map(async ({ stream, source, at, lagging: lagging2 }) => {
841
855
  const events = await this.query_array({
842
856
  stream: source,
843
857
  after: at,
844
858
  limit: eventLimit
845
859
  });
846
- return { stream, source, at, events };
860
+ return { stream, source, at, lagging: lagging2, events };
847
861
  })
848
862
  );
849
863
  if (fetched.length) {
850
864
  tracer.fetched(fetched);
851
865
  const leases = /* @__PURE__ */ new Map();
852
- const last_window_at = fetched.reduce(
866
+ const fetch_window_at = fetched.reduce(
853
867
  (max, { at, events }) => Math.max(max, events.at(-1)?.id || at),
854
868
  0
855
869
  );
856
- fetched.forEach(({ stream, events }) => {
870
+ fetched.forEach(({ stream, lagging: lagging2, events }) => {
857
871
  const payloads = events.flatMap((event) => {
858
872
  const register = this.registry.events[event.name] || [];
859
873
  return [...register.reactions.values()].filter((reaction) => {
@@ -865,16 +879,17 @@ var Act = class {
865
879
  lease: {
866
880
  stream,
867
881
  by: randomUUID2(),
868
- at: events.at(-1)?.id || last_window_at,
882
+ at: events.at(-1)?.id || fetch_window_at,
869
883
  // ff when no matching events
870
- retry: 0
884
+ retry: 0,
885
+ lagging: lagging2
871
886
  },
872
887
  // @ts-expect-error indexed by key
873
888
  payloads
874
889
  });
875
890
  });
876
891
  const leased = await store().lease(
877
- [...leases.values()].map((l) => l.lease),
892
+ [...leases.values()].map(({ lease }) => lease),
878
893
  leaseMillis
879
894
  );
880
895
  tracer.leased(leased);
@@ -883,6 +898,17 @@ var Act = class {
883
898
  (lease) => this.handle(lease, leases.get(lease.stream).payloads)
884
899
  )
885
900
  );
901
+ const [lagging_handled, leading_handled] = handled.reduce(
902
+ ([lagging_handled2, leading_handled2], { lease, handled: handled2 }) => [
903
+ lagging_handled2 + (lease.lagging ? handled2 : 0),
904
+ leading_handled2 + (lease.lagging ? 0 : handled2)
905
+ ],
906
+ [0, 0]
907
+ );
908
+ const lagging_avg = lagging > 0 ? lagging_handled / lagging : 0;
909
+ const leading_avg = leading > 0 ? leading_handled / leading : 0;
910
+ const total = lagging_avg + leading_avg;
911
+ this._drain_lag2lead_ratio = total > 0 ? Math.max(0.2, Math.min(0.8, lagging_avg / total)) : 0.5;
886
912
  const acked = await store().ack(
887
913
  handled.filter(({ error }) => !error).map(({ at, lease }) => ({ ...lease, at }))
888
914
  );
@@ -933,6 +959,7 @@ var Act = class {
933
959
  by: randomUUID2(),
934
960
  at: 0,
935
961
  retry: 0,
962
+ lagging: true,
936
963
  payloads
937
964
  }));
938
965
  const leased = await store().lease(leases, 0);