bruce-models 7.1.102 → 7.1.103

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.
@@ -12694,6 +12694,184 @@
12694
12694
  }
12695
12695
  }
12696
12696
 
12697
+ /**
12698
+ * Runs work that several callers keep asking for, at a rate the answer can actually arrive at.
12699
+ */
12700
+ (function (RequestLane) {
12701
+ RequestLane.DISPOSED = "RequestLane disposed";
12702
+ RequestLane.TIMED_OUT = "RequestLane timed out";
12703
+ /**
12704
+ * A set of independently rate-limited keys.
12705
+ * One per subject, eg. one lane for Entity reads with the Entity ID as the key.
12706
+ */
12707
+ class Lane {
12708
+ constructor(options = {}) {
12709
+ this.options = options;
12710
+ this.pending = new Map();
12711
+ this.inFlight = new Set();
12712
+ this.lastStarted = new Map();
12713
+ this.timers = new Map();
12714
+ // Keys with a pump owed at the end of this turn.
12715
+ this.scheduled = new Set();
12716
+ this.disposed = false;
12717
+ }
12718
+ /**
12719
+ * Asks for this work to be run for this key, and resolves with whatever run answers for it.
12720
+ * @param key what is being asked about, eg: an Entity ID.
12721
+ * @param work how to find out.
12722
+ */
12723
+ Run(key, work) {
12724
+ if (this.disposed) {
12725
+ return Promise.reject(new Error(RequestLane.DISPOSED));
12726
+ }
12727
+ return new Promise((resolve, reject) => {
12728
+ const slot = this.pending.get(key);
12729
+ if (slot) {
12730
+ // Newest wins: the older work has been overtaken, but whoever asked for it is
12731
+ // still owed an answer, so their waiter stays.
12732
+ slot.work = work;
12733
+ slot.waiters.push({ resolve, reject });
12734
+ }
12735
+ else {
12736
+ this.pending.set(key, { work, waiters: [{ resolve, reject }] });
12737
+ }
12738
+ this.schedulePump(key);
12739
+ });
12740
+ }
12741
+ /**
12742
+ * Whether a run is currently out for this key.
12743
+ */
12744
+ IsRunning(key) {
12745
+ return this.inFlight.has(key);
12746
+ }
12747
+ /**
12748
+ * How long this key must wait before it may run again, zero when it may run now.
12749
+ */
12750
+ WaitFor(key) {
12751
+ const minInterval = this.options.minIntervalMs || 0;
12752
+ if (!minInterval) {
12753
+ return 0;
12754
+ }
12755
+ const last = this.lastStarted.get(key);
12756
+ if (last == null) {
12757
+ return 0;
12758
+ }
12759
+ const now = (this.options.now || Date.now)();
12760
+ return Math.max(0, (last + minInterval) - now);
12761
+ }
12762
+ /**
12763
+ * Forgets a key, answering whatever was waiting on it. For a caller that has gone away.
12764
+ * @param key
12765
+ */
12766
+ Drop(key) {
12767
+ const timer = this.timers.get(key);
12768
+ if (timer != null) {
12769
+ clearTimeout(timer);
12770
+ this.timers.delete(key);
12771
+ }
12772
+ const slot = this.pending.get(key);
12773
+ if (slot) {
12774
+ this.pending.delete(key);
12775
+ this.rejectAll(slot, new Error(RequestLane.DISPOSED));
12776
+ }
12777
+ }
12778
+ Dispose() {
12779
+ this.disposed = true;
12780
+ for (const timer of Array.from(this.timers.values())) {
12781
+ clearTimeout(timer);
12782
+ }
12783
+ this.timers.clear();
12784
+ this.scheduled.clear();
12785
+ for (const slot of Array.from(this.pending.values())) {
12786
+ this.rejectAll(slot, new Error(RequestLane.DISPOSED));
12787
+ }
12788
+ this.pending.clear();
12789
+ this.inFlight.clear();
12790
+ this.lastStarted.clear();
12791
+ }
12792
+ /*
12793
+ * Answers every waiter on a slot with the same failure.
12794
+ */
12795
+ rejectAll(slot, error) {
12796
+ for (const waiter of slot.waiters) {
12797
+ waiter.reject(error);
12798
+ }
12799
+ }
12800
+ /*
12801
+ * Runs the pump at the end of this turn rather than during it.
12802
+ */
12803
+ schedulePump(key) {
12804
+ if (this.disposed || this.scheduled.has(key)) {
12805
+ return;
12806
+ }
12807
+ this.scheduled.add(key);
12808
+ Promise.resolve().then(() => {
12809
+ this.scheduled.delete(key);
12810
+ this.pump(key);
12811
+ });
12812
+ }
12813
+ /*
12814
+ * Starts the next run for a key when it has one and is allowed to.
12815
+ */
12816
+ pump(key) {
12817
+ if (this.disposed || this.inFlight.has(key) || !this.pending.has(key)) {
12818
+ return;
12819
+ }
12820
+ const waitFor = this.WaitFor(key);
12821
+ if (waitFor > 0) {
12822
+ // Whatever else is asked for during the wait folds into the same slot, so the run
12823
+ // that eventually goes is the newest one rather than the one that started the wait.
12824
+ if (!this.timers.has(key)) {
12825
+ this.timers.set(key, setTimeout(() => {
12826
+ this.timers.delete(key);
12827
+ this.pump(key);
12828
+ }, waitFor));
12829
+ }
12830
+ return;
12831
+ }
12832
+ const slot = this.pending.get(key);
12833
+ this.pending.delete(key);
12834
+ this.inFlight.add(key);
12835
+ this.lastStarted.set(key, (this.options.now || Date.now)());
12836
+ let settled = false;
12837
+ const finish = (settle) => {
12838
+ if (settled) {
12839
+ return;
12840
+ }
12841
+ settled = true;
12842
+ this.inFlight.delete(key);
12843
+ settle();
12844
+ if (!this.disposed) {
12845
+ this.schedulePump(key);
12846
+ }
12847
+ };
12848
+ const timeoutMs = this.options.timeoutMs || 0;
12849
+ let timeout = null;
12850
+ if (timeoutMs > 0) {
12851
+ timeout = setTimeout(() => finish(() => this.rejectAll(slot, new Error(RequestLane.TIMED_OUT))), timeoutMs);
12852
+ }
12853
+ // Wrapped rather than called directly, so work that throws before returning a promise is
12854
+ // a rejection like any other rather than something that leaves the key held forever.
12855
+ Promise.resolve().then(slot.work).then((value) => {
12856
+ if (timeout != null) {
12857
+ clearTimeout(timeout);
12858
+ }
12859
+ finish(() => {
12860
+ for (const waiter of slot.waiters) {
12861
+ waiter.resolve(value);
12862
+ }
12863
+ });
12864
+ }, (error) => {
12865
+ if (timeout != null) {
12866
+ clearTimeout(timeout);
12867
+ }
12868
+ finish(() => this.rejectAll(slot, error));
12869
+ });
12870
+ }
12871
+ }
12872
+ RequestLane.Lane = Lane;
12873
+ })(exports.RequestLane || (exports.RequestLane = {}));
12874
+
12697
12875
  /**
12698
12876
  * Describes a Bruce stored date.
12699
12877
  */
@@ -23727,7 +23905,7 @@
23727
23905
  }
23728
23906
 
23729
23907
  // This is updated with the package.json version on build.
23730
- const VERSION = "7.1.102";
23908
+ const VERSION = "7.1.103";
23731
23909
 
23732
23910
  exports.VERSION = VERSION;
23733
23911
  exports.AbstractApi = AbstractApi;