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.
- package/dist/bruce-models.es5.js +181 -2
- package/dist/bruce-models.es5.js.map +1 -1
- package/dist/bruce-models.umd.js +179 -1
- package/dist/bruce-models.umd.js.map +1 -1
- package/dist/lib/bruce-models.js +2 -1
- package/dist/lib/bruce-models.js.map +1 -1
- package/dist/lib/common/request-lane.js +182 -0
- package/dist/lib/common/request-lane.js.map +1 -0
- package/dist/types/bruce-models.d.ts +2 -1
- package/dist/types/common/request-lane.d.ts +49 -0
- package/package.json +1 -1
package/dist/bruce-models.umd.js
CHANGED
|
@@ -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.
|
|
23908
|
+
const VERSION = "7.1.103";
|
|
23731
23909
|
|
|
23732
23910
|
exports.VERSION = VERSION;
|
|
23733
23911
|
exports.AbstractApi = AbstractApi;
|