@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.
Files changed (45) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +20 -0
  3. package/dist/CHANGELOG.md +83 -0
  4. package/dist/LICENSE +15 -0
  5. package/dist/README.md +150 -0
  6. package/dist/index.cjs +2209 -942
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.cts +537 -280
  9. package/dist/index.d.cts.map +1 -1
  10. package/dist/index.d.mts +538 -281
  11. package/dist/index.d.mts.map +1 -1
  12. package/dist/index.mjs +2213 -951
  13. package/dist/index.mjs.map +1 -1
  14. package/package.json +9 -8
  15. package/src/events/index.ts +1 -0
  16. package/src/events/types.ts +113 -0
  17. package/src/index.ts +51 -0
  18. package/src/jobs/guards.ts +220 -0
  19. package/src/jobs/index.ts +29 -0
  20. package/src/jobs/types.ts +335 -0
  21. package/src/reset.d.ts +1 -0
  22. package/src/scheduler/helpers.ts +107 -0
  23. package/src/scheduler/index.ts +5 -0
  24. package/src/scheduler/monque.ts +1309 -0
  25. package/src/scheduler/services/change-stream-handler.ts +239 -0
  26. package/src/scheduler/services/index.ts +8 -0
  27. package/src/scheduler/services/job-manager.ts +455 -0
  28. package/src/scheduler/services/job-processor.ts +301 -0
  29. package/src/scheduler/services/job-query.ts +411 -0
  30. package/src/scheduler/services/job-scheduler.ts +267 -0
  31. package/src/scheduler/services/types.ts +48 -0
  32. package/src/scheduler/types.ts +123 -0
  33. package/src/shared/errors.ts +225 -0
  34. package/src/shared/index.ts +18 -0
  35. package/src/shared/utils/backoff.ts +77 -0
  36. package/src/shared/utils/cron.ts +67 -0
  37. package/src/shared/utils/index.ts +7 -0
  38. package/src/workers/index.ts +1 -0
  39. package/src/workers/types.ts +39 -0
  40. package/dist/errors-D5ZGG2uI.cjs +0 -155
  41. package/dist/errors-D5ZGG2uI.cjs.map +0 -1
  42. package/dist/errors-DEvnqoOC.mjs +0 -3
  43. package/dist/errors-DQ2_gprw.mjs +0 -125
  44. package/dist/errors-DQ2_gprw.mjs.map +0 -1
  45. 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