@dudousxd/nestjs-durable 0.43.0 → 0.43.1
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 +44 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +44 -6
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1238,6 +1238,15 @@ var RetentionPoller = class {
|
|
|
1238
1238
|
onModuleDestroy() {
|
|
1239
1239
|
if (this.timer) clearInterval(this.timer);
|
|
1240
1240
|
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Prune one round.
|
|
1243
|
+
*
|
|
1244
|
+
* Never rejects, for the same reason {@link TimerPoller.poll} does not: it is awaited inside
|
|
1245
|
+
* `onApplicationBootstrap` (so a rejection propagates into the host's `bootstrap()` and kills the
|
|
1246
|
+
* process) and fired as `void` on the interval (so a rejection is an unhandled one, also fatal).
|
|
1247
|
+
* Pruning history is the least urgent thing this package does — a `pruneTerminalRuns` that fails
|
|
1248
|
+
* on a locked table must cost this sweep and nothing more.
|
|
1249
|
+
*/
|
|
1241
1250
|
async sweep() {
|
|
1242
1251
|
if (this.sweeping) return;
|
|
1243
1252
|
const retention = this.options.retention;
|
|
@@ -1254,6 +1263,8 @@ var RetentionPoller = class {
|
|
|
1254
1263
|
if (deleted < batchSize) break;
|
|
1255
1264
|
}
|
|
1256
1265
|
}
|
|
1266
|
+
} catch (error) {
|
|
1267
|
+
console.error("[nestjs-durable] retention sweep failed; retrying next interval:", error);
|
|
1257
1268
|
} finally {
|
|
1258
1269
|
this.sweeping = false;
|
|
1259
1270
|
}
|
|
@@ -1648,7 +1659,11 @@ var TimerPoller = class {
|
|
|
1648
1659
|
}
|
|
1649
1660
|
async onApplicationBootstrap() {
|
|
1650
1661
|
if (!isDrivingOperator(this.options)) return;
|
|
1651
|
-
this.unsubscribeEnqueued = this.engine.onEnqueued((runId) =>
|
|
1662
|
+
this.unsubscribeEnqueued = this.engine.onEnqueued((runId) => {
|
|
1663
|
+
void this.engine.runOne(runId).catch((error) => {
|
|
1664
|
+
console.error(`[nestjs-durable] could not run enqueued run ${runId}:`, error);
|
|
1665
|
+
});
|
|
1666
|
+
});
|
|
1652
1667
|
await this.poll();
|
|
1653
1668
|
const intervalMs = this.options.timerPollMs ?? 1e3;
|
|
1654
1669
|
if (intervalMs > 0) {
|
|
@@ -1660,22 +1675,45 @@ var TimerPoller = class {
|
|
|
1660
1675
|
if (this.timer) clearInterval(this.timer);
|
|
1661
1676
|
this.unsubscribeEnqueued?.();
|
|
1662
1677
|
}
|
|
1678
|
+
/**
|
|
1679
|
+
* One sweep of the engine's recovery work.
|
|
1680
|
+
*
|
|
1681
|
+
* **This method never rejects, and that is a hard requirement rather than defensiveness.** It has
|
|
1682
|
+
* exactly two callers and a rejection out of either one kills the process: on boot it is awaited
|
|
1683
|
+
* inside `onApplicationBootstrap`, so the rejection propagates through `NestApplication.init()`
|
|
1684
|
+
* into the host's `bootstrap()`; on the interval it is a fire-and-forget `void`, so it surfaces as
|
|
1685
|
+
* an unhandled rejection. Both are fatal, and both re-occur on the next boot with the same state,
|
|
1686
|
+
* so a single unrecoverable run crash-loops every worker in the deployment — taking down every
|
|
1687
|
+
* other workflow with it. A poll that goes wrong must cost this tick, not the pod.
|
|
1688
|
+
*
|
|
1689
|
+
* Each sweep is isolated separately because they are independent: a store that fails
|
|
1690
|
+
* `recoverIncomplete` says nothing about whether durable timers should still fire, and skipping
|
|
1691
|
+
* the rest of the tick would silently widen one subsystem's outage into all of them.
|
|
1692
|
+
*/
|
|
1663
1693
|
async poll() {
|
|
1664
1694
|
if (this.polling) return;
|
|
1665
1695
|
this.polling = true;
|
|
1666
1696
|
try {
|
|
1667
|
-
await this.engine.runPending();
|
|
1668
|
-
await this.engine.recoverIncomplete();
|
|
1669
|
-
await this.engine.resumeDueTimers();
|
|
1670
|
-
await this.engine.sweepTimeouts();
|
|
1697
|
+
await this.sweep("runPending", () => this.engine.runPending());
|
|
1698
|
+
await this.sweep("recoverIncomplete", () => this.engine.recoverIncomplete());
|
|
1699
|
+
await this.sweep("resumeDueTimers", () => this.engine.resumeDueTimers());
|
|
1700
|
+
await this.sweep("sweepTimeouts", () => this.engine.sweepTimeouts());
|
|
1671
1701
|
const schedules = this.options.schedules;
|
|
1672
1702
|
if (schedules && schedules.length > 0) {
|
|
1673
|
-
await (0, import_nestjs_durable_core10.runSchedules)(this.engine, schedules, Date.now());
|
|
1703
|
+
await this.sweep("schedules", () => (0, import_nestjs_durable_core10.runSchedules)(this.engine, schedules, Date.now()));
|
|
1674
1704
|
}
|
|
1675
1705
|
} finally {
|
|
1676
1706
|
this.polling = false;
|
|
1677
1707
|
}
|
|
1678
1708
|
}
|
|
1709
|
+
/** Run one sweep, absorbing and reporting its failure — see {@link poll}. */
|
|
1710
|
+
async sweep(name, run) {
|
|
1711
|
+
try {
|
|
1712
|
+
await run();
|
|
1713
|
+
} catch (error) {
|
|
1714
|
+
console.error(`[nestjs-durable] timer poll: ${name} failed; continuing:`, error);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1679
1717
|
};
|
|
1680
1718
|
TimerPoller = _ts_decorate9([
|
|
1681
1719
|
(0, import_common9.Injectable)(),
|