@monque/core 1.0.0 → 1.1.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/LICENSE +15 -0
- package/README.md +20 -0
- package/dist/CHANGELOG.md +83 -0
- package/dist/LICENSE +15 -0
- package/dist/README.md +150 -0
- package/dist/index.cjs +2209 -942
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +537 -280
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +538 -281
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2213 -951
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -8
- package/src/events/index.ts +1 -0
- package/src/events/types.ts +113 -0
- package/src/index.ts +51 -0
- package/src/jobs/guards.ts +220 -0
- package/src/jobs/index.ts +29 -0
- package/src/jobs/types.ts +335 -0
- package/src/reset.d.ts +1 -0
- package/src/scheduler/helpers.ts +107 -0
- package/src/scheduler/index.ts +5 -0
- package/src/scheduler/monque.ts +1309 -0
- package/src/scheduler/services/change-stream-handler.ts +239 -0
- package/src/scheduler/services/index.ts +8 -0
- package/src/scheduler/services/job-manager.ts +455 -0
- package/src/scheduler/services/job-processor.ts +301 -0
- package/src/scheduler/services/job-query.ts +411 -0
- package/src/scheduler/services/job-scheduler.ts +267 -0
- package/src/scheduler/services/types.ts +48 -0
- package/src/scheduler/types.ts +123 -0
- package/src/shared/errors.ts +225 -0
- package/src/shared/index.ts +18 -0
- package/src/shared/utils/backoff.ts +77 -0
- package/src/shared/utils/cron.ts +67 -0
- package/src/shared/utils/index.ts +7 -0
- package/src/workers/index.ts +1 -0
- package/src/workers/types.ts +39 -0
- package/dist/errors-D5ZGG2uI.cjs +0 -155
- package/dist/errors-D5ZGG2uI.cjs.map +0 -1
- package/dist/errors-DEvnqoOC.mjs +0 -3
- package/dist/errors-DQ2_gprw.mjs +0 -125
- package/dist/errors-DQ2_gprw.mjs.map +0 -1
- package/dist/errors-Dfli-u59.cjs +0 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Maurice de Bruyn
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
CHANGED
|
@@ -61,6 +61,10 @@ await monque.enqueue('send-email', { to: 'user@example.com', subject: 'Hello' })
|
|
|
61
61
|
// Schedule recurring jobs
|
|
62
62
|
await monque.schedule('0 9 * * *', 'daily-report', { type: 'summary' });
|
|
63
63
|
|
|
64
|
+
// Management
|
|
65
|
+
await monque.cancelJob('job-id');
|
|
66
|
+
const stats = await monque.getQueueStats();
|
|
67
|
+
|
|
64
68
|
// Graceful shutdown
|
|
65
69
|
await monque.stop();
|
|
66
70
|
```
|
|
@@ -92,6 +96,19 @@ Creates a new Monque instance.
|
|
|
92
96
|
- `stop()` - Graceful shutdown
|
|
93
97
|
- `isHealthy()` - Check scheduler health
|
|
94
98
|
|
|
99
|
+
**Management:**
|
|
100
|
+
- `getJob(id)` - Get job details
|
|
101
|
+
- `getJobs(filter)` - List jobs
|
|
102
|
+
- `getJobsWithCursor(options)` - Paginated list
|
|
103
|
+
- `getQueueStats(filter?)` - Queue statistics
|
|
104
|
+
- `cancelJob(id)` - Cancel a job
|
|
105
|
+
- `retryJob(id)` - Retry a job
|
|
106
|
+
- `rescheduleJob(id, date)` - Reschedule a job
|
|
107
|
+
- `deleteJob(id)` - Delete a job
|
|
108
|
+
- `cancelJobs(filter)` - Bulk cancel
|
|
109
|
+
- `retryJobs(filter)` - Bulk retry
|
|
110
|
+
- `deleteJobs(filter)` - Bulk delete
|
|
111
|
+
|
|
95
112
|
### Events
|
|
96
113
|
|
|
97
114
|
```typescript
|
|
@@ -99,6 +116,9 @@ monque.on('job:start', (job) => { /* job started */ });
|
|
|
99
116
|
monque.on('job:complete', ({ job, duration }) => { /* job completed */ });
|
|
100
117
|
monque.on('job:fail', ({ job, error, willRetry }) => { /* job failed */ });
|
|
101
118
|
monque.on('job:error', ({ error, job? }) => { /* unexpected error */ });
|
|
119
|
+
monque.on('job:cancelled', ({ job }) => { /* job cancelled */ });
|
|
120
|
+
monque.on('job:retried', ({ job, previousStatus }) => { /* job retried */ });
|
|
121
|
+
monque.on('job:deleted', ({ jobId }) => { /* job deleted */ });
|
|
102
122
|
monque.on('stale:recovered', ({ count }) => { /* stale jobs recovered */ });
|
|
103
123
|
```
|
|
104
124
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# @monque/core
|
|
2
|
+
|
|
3
|
+
## 1.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#90](https://github.com/ueberBrot/monque/pull/90) [`0364f4b`](https://github.com/ueberBrot/monque/commit/0364f4b9452bc6b81961fce896ebcaeecbaafa58) Thanks [@ueberBrot](https://github.com/ueberBrot)! - Add missing LICENSE and optimize build configuration (source maps, quality gates) for better developer experience and reliability.
|
|
8
|
+
|
|
9
|
+
## 1.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#75](https://github.com/ueberBrot/monque/pull/75) [`ebb3a23`](https://github.com/ueberBrot/monque/commit/ebb3a230ec1cd59f381cd22dca19d71b0e568829) Thanks [@ueberBrot](https://github.com/ueberBrot)! - **Management APIs**: Introduced a comprehensive suite of management APIs for monitoring and controlling job queues:
|
|
14
|
+
|
|
15
|
+
- **Single Job Management**: `cancelJob`, `retryJob`, `rescheduleJob`, `deleteJob`
|
|
16
|
+
- **Bulk Operations**: `cancelJobs`, `retryJobs`, `deleteJobs` with rich filtering
|
|
17
|
+
- **Cursor Pagination**: `getJobsWithCursor` for stable, efficient iteration over large datasets
|
|
18
|
+
- **Statistics**: `getQueueStats` for monitoring queue health and performance
|
|
19
|
+
|
|
20
|
+
**Events**: New events for observability include `job:cancelled`, `job:retried`, and `job:deleted`.
|
|
21
|
+
|
|
22
|
+
## 1.0.0
|
|
23
|
+
|
|
24
|
+
### Major Changes
|
|
25
|
+
|
|
26
|
+
- [#72](https://github.com/ueberBrot/monque/pull/72) [`448bc3e`](https://github.com/ueberBrot/monque/commit/448bc3ee2fddc1e7f5911331fec19e8995ac44ff) Thanks [@ueberBrot](https://github.com/ueberBrot)! - v1.0.0 Stable Release
|
|
27
|
+
|
|
28
|
+
## 0.3.0
|
|
29
|
+
|
|
30
|
+
### Minor Changes
|
|
31
|
+
|
|
32
|
+
- [#67](https://github.com/ueberBrot/monque/pull/67) [`75fafcd`](https://github.com/ueberBrot/monque/commit/75fafcd474277de581d127bc6b60e73f04dff9dc) Thanks [@renovate](https://github.com/apps/renovate)! - chore(deps): update dependencies
|
|
33
|
+
|
|
34
|
+
- @monque/core: cron-parser (^5.4.0 → ^5.5.0)
|
|
35
|
+
|
|
36
|
+
## 0.2.0
|
|
37
|
+
|
|
38
|
+
### Minor Changes
|
|
39
|
+
|
|
40
|
+
- [#7](https://github.com/ueberBrot/monque/pull/7) [`eab1ab7`](https://github.com/ueberBrot/monque/commit/eab1ab710db66f84ad5d7edb9f42864619a1276f) Thanks [@ochrstn](https://github.com/ochrstn)! - API Rename: `worker()` → `register()`
|
|
41
|
+
|
|
42
|
+
The public method for registering job handlers has been renamed from `worker()` to `register()` for improved API clarity.
|
|
43
|
+
|
|
44
|
+
**Before:**
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
monque.worker("send-email", async (job) => {
|
|
48
|
+
await sendEmail(job.data);
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**After:**
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
monque.register("send-email", async (job) => {
|
|
56
|
+
await sendEmail(job.data);
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
This is a **breaking change** for users upgrading from earlier versions. Update all `monque.worker()` calls to `monque.register()`.
|
|
61
|
+
|
|
62
|
+
- [#29](https://github.com/ueberBrot/monque/pull/29) [`5ac7759`](https://github.com/ueberBrot/monque/commit/5ac775965f9f2ab27211b02d7b048613e48705b2) Thanks [@ueberBrot](https://github.com/ueberBrot)! - Upgrade Node.js Engine to >=22.0.0
|
|
63
|
+
|
|
64
|
+
This release updates the `engines.node` requirement in `package.json` to `>=22.0.0`.
|
|
65
|
+
|
|
66
|
+
**Breaking Change:** Users on Node.js versions older than 22.0.0 will no longer be able to install or use this package. Please upgrade to Node.js 22 (LTS) or later.
|
|
67
|
+
|
|
68
|
+
### Patch Changes
|
|
69
|
+
|
|
70
|
+
- [#48](https://github.com/ueberBrot/monque/pull/48) [`f37b90d`](https://github.com/ueberBrot/monque/commit/f37b90d51ab2773c405c34d423ce1810bbe50273) Thanks [@ueberBrot](https://github.com/ueberBrot)! - Fix race condition in `poll()` where jobs could be processed after shutdown was initiated.
|
|
71
|
+
|
|
72
|
+
## 0.1.0
|
|
73
|
+
|
|
74
|
+
### Minor Changes
|
|
75
|
+
|
|
76
|
+
- [`fe193bb`](https://github.com/ueberBrot/monque/commit/fe193bb3d840667dded3c3ea093a464d3b1852ba) Thanks [@ueberBrot](https://github.com/ueberBrot)! - Initial pre-release of Monque core.
|
|
77
|
+
|
|
78
|
+
- MongoDB-backed scheduler with atomic claiming/locking to prevent duplicate processing across multiple instances.
|
|
79
|
+
- Workers + concurrency controls for background job processing.
|
|
80
|
+
- Enqueue immediate jobs and schedule recurring jobs via 5-field cron expressions.
|
|
81
|
+
- Built-in retries with configurable exponential backoff.
|
|
82
|
+
- Heartbeats, stale job detection, and recovery on startup.
|
|
83
|
+
- Event-driven observability for job lifecycle events (with change streams support and polling as a safety net).
|
package/dist/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Maurice de Bruyn
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/dist/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="../../assets/logo.svg" width="180" alt="Monque logo" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">@monque/core</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/@monque/core">
|
|
9
|
+
<img src="https://img.shields.io/npm/v/%40monque%2Fcore?style=for-the-badge&label=%40monque%2Fcore" alt="@monque/core version" />
|
|
10
|
+
</a>
|
|
11
|
+
<a href="https://codecov.io/gh/ueberBrot/monque">
|
|
12
|
+
<img src="https://img.shields.io/codecov/c/github/ueberBrot/monque?style=for-the-badge&logo=codecov&logoColor=white" alt="Codecov" />
|
|
13
|
+
</a>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<p align="center">MongoDB-backed job scheduler with atomic locking, exponential backoff, and cron scheduling.</p>
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
Using Bun:
|
|
21
|
+
```bash
|
|
22
|
+
bun add @monque/core mongodb
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or using npm/yarn/pnpm:
|
|
26
|
+
```bash
|
|
27
|
+
npm install @monque/core mongodb
|
|
28
|
+
yarn add @monque/core mongodb
|
|
29
|
+
pnpm add @monque/core mongodb
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { Monque } from '@monque/core';
|
|
36
|
+
import { MongoClient } from 'mongodb';
|
|
37
|
+
|
|
38
|
+
const client = new MongoClient('mongodb://localhost:27017');
|
|
39
|
+
await client.connect();
|
|
40
|
+
|
|
41
|
+
const monque = new Monque(client.db('myapp'), {
|
|
42
|
+
collectionName: 'jobs',
|
|
43
|
+
pollInterval: 1000,
|
|
44
|
+
maxRetries: 10,
|
|
45
|
+
defaultConcurrency: 5,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
await monque.initialize();
|
|
49
|
+
|
|
50
|
+
// Register workers
|
|
51
|
+
monque.register('send-email', async (job) => {
|
|
52
|
+
await sendEmail(job.data.to, job.data.subject);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Start processing
|
|
56
|
+
monque.start();
|
|
57
|
+
|
|
58
|
+
// Enqueue jobs
|
|
59
|
+
await monque.enqueue('send-email', { to: 'user@example.com', subject: 'Hello' });
|
|
60
|
+
|
|
61
|
+
// Schedule recurring jobs
|
|
62
|
+
await monque.schedule('0 9 * * *', 'daily-report', { type: 'summary' });
|
|
63
|
+
|
|
64
|
+
// Management
|
|
65
|
+
await monque.cancelJob('job-id');
|
|
66
|
+
const stats = await monque.getQueueStats();
|
|
67
|
+
|
|
68
|
+
// Graceful shutdown
|
|
69
|
+
await monque.stop();
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## API
|
|
73
|
+
|
|
74
|
+
### `new Monque(db, options?)`
|
|
75
|
+
|
|
76
|
+
Creates a new Monque instance.
|
|
77
|
+
|
|
78
|
+
**Options:**
|
|
79
|
+
- `collectionName` - MongoDB collection name (default: `'monque_jobs'`)
|
|
80
|
+
- `pollInterval` - Polling interval in ms (default: `1000`)
|
|
81
|
+
- `maxRetries` - Max retry attempts (default: `10`)
|
|
82
|
+
- `baseRetryInterval` - Base backoff interval in ms (default: `1000`)
|
|
83
|
+
- `shutdownTimeout` - Graceful shutdown timeout in ms (default: `30000`)
|
|
84
|
+
- `defaultConcurrency` - Jobs per worker (default: `5`)
|
|
85
|
+
- `lockTimeout` - Stale job threshold in ms (default: `1800000`)
|
|
86
|
+
- `recoverStaleJobs` - Recover stale jobs on startup (default: `true`)
|
|
87
|
+
|
|
88
|
+
### Methods
|
|
89
|
+
|
|
90
|
+
- `initialize()` - Set up collection and indexes
|
|
91
|
+
- `enqueue(name, data, options?)` - Enqueue a job
|
|
92
|
+
- `now(name, data)` - Enqueue for immediate processing
|
|
93
|
+
- `schedule(cron, name, data)` - Schedule recurring job
|
|
94
|
+
- `register(name, handler, options?)` - Register a worker
|
|
95
|
+
- `start()` - Start processing jobs
|
|
96
|
+
- `stop()` - Graceful shutdown
|
|
97
|
+
- `isHealthy()` - Check scheduler health
|
|
98
|
+
|
|
99
|
+
**Management:**
|
|
100
|
+
- `getJob(id)` - Get job details
|
|
101
|
+
- `getJobs(filter)` - List jobs
|
|
102
|
+
- `getJobsWithCursor(options)` - Paginated list
|
|
103
|
+
- `getQueueStats(filter?)` - Queue statistics
|
|
104
|
+
- `cancelJob(id)` - Cancel a job
|
|
105
|
+
- `retryJob(id)` - Retry a job
|
|
106
|
+
- `rescheduleJob(id, date)` - Reschedule a job
|
|
107
|
+
- `deleteJob(id)` - Delete a job
|
|
108
|
+
- `cancelJobs(filter)` - Bulk cancel
|
|
109
|
+
- `retryJobs(filter)` - Bulk retry
|
|
110
|
+
- `deleteJobs(filter)` - Bulk delete
|
|
111
|
+
|
|
112
|
+
### Events
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
monque.on('job:start', (job) => { /* job started */ });
|
|
116
|
+
monque.on('job:complete', ({ job, duration }) => { /* job completed */ });
|
|
117
|
+
monque.on('job:fail', ({ job, error, willRetry }) => { /* job failed */ });
|
|
118
|
+
monque.on('job:error', ({ error, job? }) => { /* unexpected error */ });
|
|
119
|
+
monque.on('job:cancelled', ({ job }) => { /* job cancelled */ });
|
|
120
|
+
monque.on('job:retried', ({ job, previousStatus }) => { /* job retried */ });
|
|
121
|
+
monque.on('job:deleted', ({ jobId }) => { /* job deleted */ });
|
|
122
|
+
monque.on('stale:recovered', ({ count }) => { /* stale jobs recovered */ });
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Development
|
|
126
|
+
|
|
127
|
+
### Running Tests
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# Run tests once (fresh container each time)
|
|
131
|
+
bun run test
|
|
132
|
+
|
|
133
|
+
# Run tests in watch mode with container reuse (faster iteration)
|
|
134
|
+
bun run test:dev
|
|
135
|
+
|
|
136
|
+
# Or enable reuse globally in your shell profile
|
|
137
|
+
export TESTCONTAINERS_REUSE_ENABLE=true
|
|
138
|
+
bun run test:watch
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
When `TESTCONTAINERS_REUSE_ENABLE=true`, the MongoDB testcontainer persists between test runs, significantly speeding up local development. Ryuk (the testcontainers cleanup daemon) remains enabled as a safety net for orphaned containers.
|
|
142
|
+
|
|
143
|
+
To manually clean up reusable containers:
|
|
144
|
+
```bash
|
|
145
|
+
docker ps -q --filter label=org.testcontainers=true | while read -r id; do docker stop "$id"; done
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
ISC
|