@dudousxd/nestjs-durable 0.46.0 → 0.46.2
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 +82 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +82 -9
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1173,6 +1173,31 @@ ProxyRunGateway = _ts_decorate6([
|
|
|
1173
1173
|
// src/retention-poller.ts
|
|
1174
1174
|
import { DURABLE_OPTIONS_CANONICAL as DURABLE_OPTIONS_CANONICAL4, STATE_STORE_CANONICAL, TERMINAL_RUN_STATUSES, parseDuration } from "@dudousxd/nestjs-durable-core";
|
|
1175
1175
|
import { Inject as Inject4, Injectable as Injectable7 } from "@nestjs/common";
|
|
1176
|
+
|
|
1177
|
+
// src/settle-within.ts
|
|
1178
|
+
async function settleWithin(p, timeoutMs) {
|
|
1179
|
+
let timer;
|
|
1180
|
+
let timedOut = false;
|
|
1181
|
+
const timeout = new Promise((resolve) => {
|
|
1182
|
+
timer = setTimeout(() => {
|
|
1183
|
+
timedOut = true;
|
|
1184
|
+
resolve();
|
|
1185
|
+
}, timeoutMs);
|
|
1186
|
+
timer.unref?.();
|
|
1187
|
+
});
|
|
1188
|
+
try {
|
|
1189
|
+
await Promise.race([
|
|
1190
|
+
p.then(void 0, () => void 0),
|
|
1191
|
+
timeout
|
|
1192
|
+
]);
|
|
1193
|
+
} finally {
|
|
1194
|
+
if (timer) clearTimeout(timer);
|
|
1195
|
+
}
|
|
1196
|
+
return timedOut;
|
|
1197
|
+
}
|
|
1198
|
+
__name(settleWithin, "settleWithin");
|
|
1199
|
+
|
|
1200
|
+
// src/retention-poller.ts
|
|
1176
1201
|
function _ts_decorate7(decorators, target, key, desc) {
|
|
1177
1202
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1178
1203
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -1243,6 +1268,9 @@ var RetentionPoller = class {
|
|
|
1243
1268
|
options;
|
|
1244
1269
|
timer;
|
|
1245
1270
|
sweeping = false;
|
|
1271
|
+
stopping = false;
|
|
1272
|
+
/** The sweep in flight, so shutdown can wait for it before the store closes. */
|
|
1273
|
+
current;
|
|
1246
1274
|
constructor(store, options) {
|
|
1247
1275
|
this.store = store;
|
|
1248
1276
|
this.options = options;
|
|
@@ -1270,8 +1298,18 @@ var RetentionPoller = class {
|
|
|
1270
1298
|
this.timer.unref?.();
|
|
1271
1299
|
}
|
|
1272
1300
|
}
|
|
1273
|
-
|
|
1301
|
+
/** Stop sweeping and wait for the sweep in flight (bounded by `shutdownTimeoutMs`, default 10s),
|
|
1302
|
+
* so no prune is still pending when the host closes its connection pool. This wait runs concurrently
|
|
1303
|
+
* with the timer poller's and is NOT deducted from the engine's drain budget (the retention poller
|
|
1304
|
+
* holds no engine), so a slow prune can add up to one more `shutdownTimeoutMs` before the drain. */
|
|
1305
|
+
async onModuleDestroy() {
|
|
1274
1306
|
if (this.timer) clearInterval(this.timer);
|
|
1307
|
+
this.stopping = true;
|
|
1308
|
+
if (!this.current) return;
|
|
1309
|
+
const budget = this.options.shutdownTimeoutMs ?? 1e4;
|
|
1310
|
+
if (await settleWithin(this.current, budget)) {
|
|
1311
|
+
console.warn(`[nestjs-durable] retention sweep still running after ${budget}ms at shutdown; continuing`);
|
|
1312
|
+
}
|
|
1275
1313
|
}
|
|
1276
1314
|
/**
|
|
1277
1315
|
* Prune one round.
|
|
@@ -1282,8 +1320,16 @@ var RetentionPoller = class {
|
|
|
1282
1320
|
* Pruning history is the least urgent thing this package does — a `pruneTerminalRuns` that fails
|
|
1283
1321
|
* on a locked table must cost this sweep and nothing more.
|
|
1284
1322
|
*/
|
|
1285
|
-
|
|
1286
|
-
if (this.sweeping) return;
|
|
1323
|
+
sweep() {
|
|
1324
|
+
if (this.sweeping) return this.current ?? Promise.resolve();
|
|
1325
|
+
const run = this.sweepOnce().finally(() => {
|
|
1326
|
+
if (this.current === run) this.current = void 0;
|
|
1327
|
+
});
|
|
1328
|
+
this.current = run;
|
|
1329
|
+
return run;
|
|
1330
|
+
}
|
|
1331
|
+
async sweepOnce() {
|
|
1332
|
+
if (this.stopping) return;
|
|
1287
1333
|
const retention = this.options.retention;
|
|
1288
1334
|
const store = this.requireStore();
|
|
1289
1335
|
const prune = store.pruneTerminalRuns;
|
|
@@ -1294,6 +1340,7 @@ var RetentionPoller = class {
|
|
|
1294
1340
|
const now = Date.now();
|
|
1295
1341
|
for (const policy of retention.policies) {
|
|
1296
1342
|
for (let batch = 0; batch < MAX_BATCHES_PER_POLICY; batch++) {
|
|
1343
|
+
if (this.stopping) return;
|
|
1297
1344
|
const deleted = await prune.call(store, policy, now, batchSize);
|
|
1298
1345
|
if (deleted < batchSize) break;
|
|
1299
1346
|
}
|
|
@@ -1705,6 +1752,8 @@ var TimerPoller = class {
|
|
|
1705
1752
|
options;
|
|
1706
1753
|
timer;
|
|
1707
1754
|
polling = false;
|
|
1755
|
+
/** The sweep in flight, so shutdown can wait for it instead of racing the store's close. */
|
|
1756
|
+
current;
|
|
1708
1757
|
unsubscribeEnqueued;
|
|
1709
1758
|
constructor(engine, options) {
|
|
1710
1759
|
this.engine = engine;
|
|
@@ -1724,9 +1773,27 @@ var TimerPoller = class {
|
|
|
1724
1773
|
this.timer.unref?.();
|
|
1725
1774
|
}
|
|
1726
1775
|
}
|
|
1727
|
-
|
|
1776
|
+
/**
|
|
1777
|
+
* Stop polling and wait for the sweep in flight (bounded by `shutdownTimeoutMs`, default 10s).
|
|
1778
|
+
* Nest runs every `onModuleDestroy` before any `onApplicationShutdown`, so returning here only once
|
|
1779
|
+
* the sweep has settled means no store call is still pending when the registrar drains and the
|
|
1780
|
+
* host closes its connection pool. The engine is told to stop first so a sweep working through a
|
|
1781
|
+
* backlog stops locking runs instead of finishing the backlog. The time spent waiting is deducted
|
|
1782
|
+
* from the later `engine.drain()`, so poll wait plus drain stay within one `shutdownTimeoutMs`.
|
|
1783
|
+
*/
|
|
1784
|
+
async onModuleDestroy() {
|
|
1728
1785
|
if (this.timer) clearInterval(this.timer);
|
|
1729
1786
|
this.unsubscribeEnqueued?.();
|
|
1787
|
+
if (!isDrivingOperator(this.options)) return;
|
|
1788
|
+
this.engine.beginDrain?.();
|
|
1789
|
+
if (!this.current) return;
|
|
1790
|
+
const budget = this.options.shutdownTimeoutMs ?? 1e4;
|
|
1791
|
+
const started = Date.now();
|
|
1792
|
+
const timedOut = await settleWithin(this.current, budget);
|
|
1793
|
+
this.engine.beginDrain?.(Date.now() - started);
|
|
1794
|
+
if (timedOut) {
|
|
1795
|
+
console.warn(`[nestjs-durable] timer poll still running after ${budget}ms at shutdown; continuing (it may report store errors if the host ends its pool now)`);
|
|
1796
|
+
}
|
|
1730
1797
|
}
|
|
1731
1798
|
/**
|
|
1732
1799
|
* One sweep of the engine's recovery work.
|
|
@@ -1743,10 +1810,18 @@ var TimerPoller = class {
|
|
|
1743
1810
|
* `recoverIncomplete` says nothing about whether durable timers should still fire, and skipping
|
|
1744
1811
|
* the rest of the tick would silently widen one subsystem's outage into all of them.
|
|
1745
1812
|
*/
|
|
1746
|
-
|
|
1747
|
-
if (this.polling) return;
|
|
1813
|
+
poll() {
|
|
1814
|
+
if (this.polling) return this.current ?? Promise.resolve();
|
|
1748
1815
|
this.polling = true;
|
|
1749
|
-
|
|
1816
|
+
const run = this.pollOnce().finally(() => {
|
|
1817
|
+
this.polling = false;
|
|
1818
|
+
if (this.current === run) this.current = void 0;
|
|
1819
|
+
});
|
|
1820
|
+
this.current = run;
|
|
1821
|
+
return run;
|
|
1822
|
+
}
|
|
1823
|
+
async pollOnce() {
|
|
1824
|
+
{
|
|
1750
1825
|
await this.sweep("runPending", () => this.engine.runPending());
|
|
1751
1826
|
await this.sweep("recoverIncomplete", () => this.engine.recoverIncomplete());
|
|
1752
1827
|
await this.sweep("resumeDueTimers", () => this.engine.resumeDueTimers());
|
|
@@ -1758,8 +1833,6 @@ var TimerPoller = class {
|
|
|
1758
1833
|
if (this.options.persistedSchedules) {
|
|
1759
1834
|
await this.sweep("persistedSchedules", () => this.engine.schedules.tick());
|
|
1760
1835
|
}
|
|
1761
|
-
} finally {
|
|
1762
|
-
this.polling = false;
|
|
1763
1836
|
}
|
|
1764
1837
|
}
|
|
1765
1838
|
/** Run one sweep, absorbing and reporting its failure — see {@link poll}. */
|