@adaptic/utils 0.0.1002 → 0.0.1004
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.cjs +766 -235
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +766 -235
- package/dist/index.mjs.map +1 -1
- package/dist/test.js +70 -0
- package/dist/test.js.map +1 -1
- package/dist/types/__tests__/stampede-load-timeout.test.d.ts +2 -0
- package/dist/types/__tests__/stampede-load-timeout.test.d.ts.map +1 -0
- package/dist/types/alpaca-trading-api.d.ts +68 -4
- package/dist/types/alpaca-trading-api.d.ts.map +1 -1
- package/dist/types/cache/stampede-protected-cache.d.ts +28 -0
- package/dist/types/cache/stampede-protected-cache.d.ts.map +1 -1
- package/dist/types/crypto.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -4
- package/dist/types/performance-metrics.d.ts.map +1 -1
- package/dist/types/price-utils.d.ts.map +1 -1
- package/dist/types/rate-limiter.d.ts +21 -0
- package/dist/types/rate-limiter.d.ts.map +1 -1
- package/dist/types/types/alpaca-types.d.ts +1 -0
- package/dist/types/types/alpaca-types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/test.js
CHANGED
|
@@ -1597,6 +1597,19 @@ class RateLimitError extends AdapticUtilsError {
|
|
|
1597
1597
|
* const result = await makeAlpacaApiCall();
|
|
1598
1598
|
* ```
|
|
1599
1599
|
*/
|
|
1600
|
+
/** Number of milliseconds in one second, used for token-refill timing math. */
|
|
1601
|
+
const MS_PER_SECOND = 1000;
|
|
1602
|
+
/**
|
|
1603
|
+
* Minimum delay (ms) for a scheduled queue wake-up. Guards against a `0`/`NaN`
|
|
1604
|
+
* delay when the token deficit rounds down, ensuring the timer always makes
|
|
1605
|
+
* forward progress rather than busy-looping on the event loop.
|
|
1606
|
+
*/
|
|
1607
|
+
const MIN_WAKE_DELAY_MS = 1;
|
|
1608
|
+
/**
|
|
1609
|
+
* Number of whole tokens required to release a single queued request. The token
|
|
1610
|
+
* bucket consumes exactly one token per admitted request.
|
|
1611
|
+
*/
|
|
1612
|
+
const TOKENS_PER_REQUEST = 1;
|
|
1600
1613
|
/**
|
|
1601
1614
|
* Token bucket rate limiter implementation
|
|
1602
1615
|
*
|
|
@@ -1612,6 +1625,13 @@ class TokenBucketRateLimiter {
|
|
|
1612
1625
|
queue = [];
|
|
1613
1626
|
timeoutMs;
|
|
1614
1627
|
processingQueue = false;
|
|
1628
|
+
/**
|
|
1629
|
+
* Single pending timer that wakes the limiter to refill tokens and drain the
|
|
1630
|
+
* queue. Without this, a queued request would only be released by a
|
|
1631
|
+
* subsequent {@link acquire} call and would otherwise stall until its own
|
|
1632
|
+
* timeout fired. `null` means no wake-up is currently scheduled.
|
|
1633
|
+
*/
|
|
1634
|
+
wakeTimer = null;
|
|
1615
1635
|
/**
|
|
1616
1636
|
* Creates a new rate limiter instance
|
|
1617
1637
|
*
|
|
@@ -1685,8 +1705,48 @@ class TokenBucketRateLimiter {
|
|
|
1685
1705
|
reject(error);
|
|
1686
1706
|
}, this.timeoutMs);
|
|
1687
1707
|
this.queue.push({ resolve, reject, timeoutHandle });
|
|
1708
|
+
// Ensure the queue is actively drained even if no further acquire() calls
|
|
1709
|
+
// arrive: schedule a wake-up to refill tokens and release this request.
|
|
1710
|
+
this.scheduleQueueWake();
|
|
1688
1711
|
});
|
|
1689
1712
|
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Schedules a single wake-up timer that refills tokens and drains the queue.
|
|
1715
|
+
*
|
|
1716
|
+
* The delay is the time required to accrue the tokens still needed to release
|
|
1717
|
+
* the next queued request at the configured refill rate. Only one timer is
|
|
1718
|
+
* ever outstanding (guarded by {@link wakeTimer}); the timer is `unref`'d so
|
|
1719
|
+
* it never keeps the Node.js process alive on its own. When it fires it
|
|
1720
|
+
* refills, drains what it can, and re-arms itself if work remains.
|
|
1721
|
+
*/
|
|
1722
|
+
scheduleQueueWake() {
|
|
1723
|
+
// A wake-up is already pending, or there is nothing to wake for.
|
|
1724
|
+
if (this.wakeTimer !== null || this.queue.length === 0) {
|
|
1725
|
+
return;
|
|
1726
|
+
}
|
|
1727
|
+
const tokensNeeded = Math.max(0, TOKENS_PER_REQUEST - this.tokens);
|
|
1728
|
+
const deficitMs = Math.max(MIN_WAKE_DELAY_MS, Math.ceil((tokensNeeded / this.config.refillRate) * MS_PER_SECOND));
|
|
1729
|
+
const timer = setTimeout(() => {
|
|
1730
|
+
this.wakeTimer = null;
|
|
1731
|
+
// refill() drains the queue via processQueue(); if requests remain
|
|
1732
|
+
// afterwards, processQueue() re-arms the wake-up.
|
|
1733
|
+
this.refill();
|
|
1734
|
+
}, deficitMs);
|
|
1735
|
+
// Do not let a pending rate-limiter wake-up keep the process alive.
|
|
1736
|
+
if (typeof timer.unref === "function") {
|
|
1737
|
+
timer.unref();
|
|
1738
|
+
}
|
|
1739
|
+
this.wakeTimer = timer;
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* Clears any pending wake-up timer.
|
|
1743
|
+
*/
|
|
1744
|
+
clearWakeTimer() {
|
|
1745
|
+
if (this.wakeTimer !== null) {
|
|
1746
|
+
clearTimeout(this.wakeTimer);
|
|
1747
|
+
this.wakeTimer = null;
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1690
1750
|
/**
|
|
1691
1751
|
* Refills tokens based on elapsed time and processes queued requests
|
|
1692
1752
|
*
|
|
@@ -1731,6 +1791,15 @@ class TokenBucketRateLimiter {
|
|
|
1731
1791
|
finally {
|
|
1732
1792
|
this.processingQueue = false;
|
|
1733
1793
|
}
|
|
1794
|
+
// Keep the wake-up state consistent with the queue: if requests are still
|
|
1795
|
+
// waiting (tokens ran out mid-drain), ensure a wake-up is armed; otherwise
|
|
1796
|
+
// release any pending timer so it cannot fire needlessly.
|
|
1797
|
+
if (this.queue.length > 0) {
|
|
1798
|
+
this.scheduleQueueWake();
|
|
1799
|
+
}
|
|
1800
|
+
else {
|
|
1801
|
+
this.clearWakeTimer();
|
|
1802
|
+
}
|
|
1734
1803
|
}
|
|
1735
1804
|
/**
|
|
1736
1805
|
* Gets the current number of available tokens
|
|
@@ -1762,6 +1831,7 @@ class TokenBucketRateLimiter {
|
|
|
1762
1831
|
clearTimeout(request.timeoutHandle);
|
|
1763
1832
|
request.reject(new RateLimitError(`Rate limiter reset for ${this.config.label}`, this.config.label, undefined));
|
|
1764
1833
|
}
|
|
1834
|
+
this.clearWakeTimer();
|
|
1765
1835
|
this.queue = [];
|
|
1766
1836
|
this.tokens = this.config.maxTokens;
|
|
1767
1837
|
this.lastRefill = Date.now();
|