@monque/core 1.1.2 → 1.2.0
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/README.md +20 -1
- package/dist/CHANGELOG.md +10 -0
- package/dist/README.md +20 -1
- package/dist/index.cjs +43 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +40 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +43 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -14
- package/src/scheduler/monque.ts +5 -3
- package/src/scheduler/services/job-processor.ts +60 -5
- package/src/scheduler/services/types.ts +15 -3
- package/src/scheduler/types.ts +43 -1
package/README.md
CHANGED
|
@@ -8,12 +8,31 @@
|
|
|
8
8
|
<a href="https://www.npmjs.com/package/@monque/core">
|
|
9
9
|
<img src="https://img.shields.io/npm/v/%40monque%2Fcore?style=for-the-badge&label=%40monque%2Fcore" alt="@monque/core version" />
|
|
10
10
|
</a>
|
|
11
|
+
<a href="https://github.com/ueberBrot/monque/actions/workflows/ci.yml">
|
|
12
|
+
<img src="https://img.shields.io/github/actions/workflow/status/ueberBrot/monque/ci.yml?branch=main&style=for-the-badge&logo=github" alt="CI Status" />
|
|
13
|
+
</a>
|
|
11
14
|
<a href="https://codecov.io/gh/ueberBrot/monque">
|
|
12
15
|
<img src="https://img.shields.io/codecov/c/github/ueberBrot/monque?style=for-the-badge&logo=codecov&logoColor=white" alt="Codecov" />
|
|
13
16
|
</a>
|
|
17
|
+
<a href="https://opensource.org/licenses/ISC">
|
|
18
|
+
<img src="https://img.shields.io/badge/License-ISC-blue.svg?style=for-the-badge" alt="License: ISC" />
|
|
19
|
+
</a>
|
|
20
|
+
<a href="https://bun.sh">
|
|
21
|
+
<img src="https://img.shields.io/badge/Built%20with-Bun-fbf0df?style=for-the-badge&logo=bun&logoColor=black" alt="Built with Bun" />
|
|
22
|
+
</a>
|
|
14
23
|
</p>
|
|
15
24
|
|
|
16
|
-
|
|
25
|
+
A **robust, type-safe MongoDB job queue** for TypeScript with atomic locking, exponential backoff, and cron scheduling.
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- 🔒 **Atomic Locking**: Mandatory `findOneAndUpdate` for safe job acquisition in distributed environments.
|
|
30
|
+
- 📈 **Exponential Backoff**: Built-in retry logic with configurable backoff strategies.
|
|
31
|
+
- 📅 **Cron Scheduling**: Native support for recurring jobs using standard cron syntax.
|
|
32
|
+
- 🔍 **Type Safety**: Fully typed job payloads and worker definitions.
|
|
33
|
+
- ⚡ **Event-Driven**: Comprehensive event system for monitoring and logging.
|
|
34
|
+
- 🛠️ **Native Driver**: Uses the native MongoDB driver for maximum performance and compatibility.
|
|
35
|
+
- 🛑 **Graceful Shutdown**: Ensures all in-progress jobs finish or are safely released before stopping.
|
|
17
36
|
|
|
18
37
|
## Installation
|
|
19
38
|
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @monque/core
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#112](https://github.com/ueberBrot/monque/pull/112) [`9b7f44f`](https://github.com/ueberBrot/monque/commit/9b7f44f5c1f6b4aa4215e571189cc03cbaa49865) Thanks [@ueberBrot](https://github.com/ueberBrot)! - Add instance-level concurrency throttling and deprecated old naming conventions.
|
|
8
|
+
|
|
9
|
+
- Added `instanceConcurrency` option (formerly `maxConcurrency`) to limit the total number of jobs processed concurrently across all workers on a single Monque instance.
|
|
10
|
+
- Added `workerConcurrency` as a clearer alias for `defaultConcurrency`.
|
|
11
|
+
- Deprecated `maxConcurrency` and `defaultConcurrency` in favor of the new explicit names. They will be removed in the next major version.
|
|
12
|
+
|
|
3
13
|
## 1.1.2
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
package/dist/README.md
CHANGED
|
@@ -8,12 +8,31 @@
|
|
|
8
8
|
<a href="https://www.npmjs.com/package/@monque/core">
|
|
9
9
|
<img src="https://img.shields.io/npm/v/%40monque%2Fcore?style=for-the-badge&label=%40monque%2Fcore" alt="@monque/core version" />
|
|
10
10
|
</a>
|
|
11
|
+
<a href="https://github.com/ueberBrot/monque/actions/workflows/ci.yml">
|
|
12
|
+
<img src="https://img.shields.io/github/actions/workflow/status/ueberBrot/monque/ci.yml?branch=main&style=for-the-badge&logo=github" alt="CI Status" />
|
|
13
|
+
</a>
|
|
11
14
|
<a href="https://codecov.io/gh/ueberBrot/monque">
|
|
12
15
|
<img src="https://img.shields.io/codecov/c/github/ueberBrot/monque?style=for-the-badge&logo=codecov&logoColor=white" alt="Codecov" />
|
|
13
16
|
</a>
|
|
17
|
+
<a href="https://opensource.org/licenses/ISC">
|
|
18
|
+
<img src="https://img.shields.io/badge/License-ISC-blue.svg?style=for-the-badge" alt="License: ISC" />
|
|
19
|
+
</a>
|
|
20
|
+
<a href="https://bun.sh">
|
|
21
|
+
<img src="https://img.shields.io/badge/Built%20with-Bun-fbf0df?style=for-the-badge&logo=bun&logoColor=black" alt="Built with Bun" />
|
|
22
|
+
</a>
|
|
14
23
|
</p>
|
|
15
24
|
|
|
16
|
-
|
|
25
|
+
A **robust, type-safe MongoDB job queue** for TypeScript with atomic locking, exponential backoff, and cron scheduling.
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- 🔒 **Atomic Locking**: Mandatory `findOneAndUpdate` for safe job acquisition in distributed environments.
|
|
30
|
+
- 📈 **Exponential Backoff**: Built-in retry logic with configurable backoff strategies.
|
|
31
|
+
- 📅 **Cron Scheduling**: Native support for recurring jobs using standard cron syntax.
|
|
32
|
+
- 🔍 **Type Safety**: Fully typed job payloads and worker definitions.
|
|
33
|
+
- ⚡ **Event-Driven**: Comprehensive event system for monitoring and logging.
|
|
34
|
+
- 🛠️ **Native Driver**: Uses the native MongoDB driver for maximum performance and compatibility.
|
|
35
|
+
- 🛑 **Graceful Shutdown**: Ensures all in-progress jobs finish or are safely released before stopping.
|
|
17
36
|
|
|
18
37
|
## Installation
|
|
19
38
|
|
package/dist/index.cjs
CHANGED
|
@@ -1114,27 +1114,57 @@ var JobProcessor = class {
|
|
|
1114
1114
|
this.ctx = ctx;
|
|
1115
1115
|
}
|
|
1116
1116
|
/**
|
|
1117
|
+
* Get the total number of active jobs across all workers.
|
|
1118
|
+
*
|
|
1119
|
+
* Used for instance-level throttling when `instanceConcurrency` is configured.
|
|
1120
|
+
*/
|
|
1121
|
+
getTotalActiveJobs() {
|
|
1122
|
+
let total = 0;
|
|
1123
|
+
for (const worker of this.ctx.workers.values()) total += worker.activeJobs.size;
|
|
1124
|
+
return total;
|
|
1125
|
+
}
|
|
1126
|
+
/**
|
|
1127
|
+
* Get the number of available slots considering the global instanceConcurrency limit.
|
|
1128
|
+
*
|
|
1129
|
+
* @param workerAvailableSlots - Available slots for the specific worker
|
|
1130
|
+
* @returns Number of slots available after applying global limit
|
|
1131
|
+
*/
|
|
1132
|
+
getGloballyAvailableSlots(workerAvailableSlots) {
|
|
1133
|
+
const { instanceConcurrency } = this.ctx.options;
|
|
1134
|
+
if (instanceConcurrency === void 0) return workerAvailableSlots;
|
|
1135
|
+
const globalAvailable = instanceConcurrency - this.getTotalActiveJobs();
|
|
1136
|
+
return Math.min(workerAvailableSlots, globalAvailable);
|
|
1137
|
+
}
|
|
1138
|
+
/**
|
|
1117
1139
|
* Poll for available jobs and process them.
|
|
1118
1140
|
*
|
|
1119
1141
|
* Called at regular intervals (configured by `pollInterval`). For each registered worker,
|
|
1120
1142
|
* attempts to acquire jobs up to the worker's available concurrency slots.
|
|
1121
|
-
* Aborts early if the scheduler is stopping (`isRunning` is false)
|
|
1143
|
+
* Aborts early if the scheduler is stopping (`isRunning` is false) or if
|
|
1144
|
+
* the instance-level `instanceConcurrency` limit is reached.
|
|
1122
1145
|
*/
|
|
1123
1146
|
async poll() {
|
|
1124
1147
|
if (!this.ctx.isRunning()) return;
|
|
1148
|
+
const { instanceConcurrency } = this.ctx.options;
|
|
1149
|
+
if (instanceConcurrency !== void 0 && this.getTotalActiveJobs() >= instanceConcurrency) return;
|
|
1125
1150
|
for (const [name, worker] of this.ctx.workers) {
|
|
1126
|
-
const
|
|
1127
|
-
if (
|
|
1151
|
+
const workerAvailableSlots = worker.concurrency - worker.activeJobs.size;
|
|
1152
|
+
if (workerAvailableSlots <= 0) continue;
|
|
1153
|
+
const availableSlots = this.getGloballyAvailableSlots(workerAvailableSlots);
|
|
1154
|
+
if (availableSlots <= 0) return;
|
|
1128
1155
|
for (let i = 0; i < availableSlots; i++) {
|
|
1129
1156
|
if (!this.ctx.isRunning()) return;
|
|
1157
|
+
if (instanceConcurrency !== void 0 && this.getTotalActiveJobs() >= instanceConcurrency) return;
|
|
1130
1158
|
const job = await this.acquireJob(name);
|
|
1131
|
-
if (job)
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
job
|
|
1159
|
+
if (job) {
|
|
1160
|
+
worker.activeJobs.set(job._id.toString(), job);
|
|
1161
|
+
this.processJob(job, worker).catch((error) => {
|
|
1162
|
+
this.ctx.emit("job:error", {
|
|
1163
|
+
error,
|
|
1164
|
+
job
|
|
1165
|
+
});
|
|
1135
1166
|
});
|
|
1136
|
-
}
|
|
1137
|
-
else break;
|
|
1167
|
+
} else break;
|
|
1138
1168
|
}
|
|
1139
1169
|
}
|
|
1140
1170
|
}
|
|
@@ -1187,7 +1217,6 @@ var JobProcessor = class {
|
|
|
1187
1217
|
*/
|
|
1188
1218
|
async processJob(job, worker) {
|
|
1189
1219
|
const jobId = job._id.toString();
|
|
1190
|
-
worker.activeJobs.set(jobId, job);
|
|
1191
1220
|
const startTime = Date.now();
|
|
1192
1221
|
this.ctx.emit("job:start", job);
|
|
1193
1222
|
try {
|
|
@@ -1817,7 +1846,7 @@ const DEFAULTS = {
|
|
|
1817
1846
|
maxRetries: 10,
|
|
1818
1847
|
baseRetryInterval: 1e3,
|
|
1819
1848
|
shutdownTimeout: 3e4,
|
|
1820
|
-
|
|
1849
|
+
workerConcurrency: 5,
|
|
1821
1850
|
lockTimeout: 18e5,
|
|
1822
1851
|
recoverStaleJobs: true,
|
|
1823
1852
|
heartbeatInterval: 3e4,
|
|
@@ -1911,10 +1940,11 @@ var Monque = class extends node_events.EventEmitter {
|
|
|
1911
1940
|
maxRetries: options.maxRetries ?? DEFAULTS.maxRetries,
|
|
1912
1941
|
baseRetryInterval: options.baseRetryInterval ?? DEFAULTS.baseRetryInterval,
|
|
1913
1942
|
shutdownTimeout: options.shutdownTimeout ?? DEFAULTS.shutdownTimeout,
|
|
1914
|
-
|
|
1943
|
+
workerConcurrency: options.workerConcurrency ?? options.defaultConcurrency ?? DEFAULTS.workerConcurrency,
|
|
1915
1944
|
lockTimeout: options.lockTimeout ?? DEFAULTS.lockTimeout,
|
|
1916
1945
|
recoverStaleJobs: options.recoverStaleJobs ?? DEFAULTS.recoverStaleJobs,
|
|
1917
1946
|
maxBackoffDelay: options.maxBackoffDelay,
|
|
1947
|
+
instanceConcurrency: options.instanceConcurrency ?? options.maxConcurrency,
|
|
1918
1948
|
schedulerInstanceId: options.schedulerInstanceId ?? (0, node_crypto.randomUUID)(),
|
|
1919
1949
|
heartbeatInterval: options.heartbeatInterval ?? DEFAULTS.heartbeatInterval,
|
|
1920
1950
|
jobRetention: options.jobRetention
|
|
@@ -2577,7 +2607,7 @@ var Monque = class extends node_events.EventEmitter {
|
|
|
2577
2607
|
* ```
|
|
2578
2608
|
*/
|
|
2579
2609
|
register(name, handler, options = {}) {
|
|
2580
|
-
const concurrency = options.concurrency ?? this.options.
|
|
2610
|
+
const concurrency = options.concurrency ?? this.options.workerConcurrency;
|
|
2581
2611
|
if (this.workers.has(name) && options.replace !== true) throw new WorkerRegistrationError(`Worker already registered for job name "${name}". Use { replace: true } to replace.`, name);
|
|
2582
2612
|
this.workers.set(name, {
|
|
2583
2613
|
handler,
|