@monque/core 1.1.0 → 1.1.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/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.
@@ -0,0 +1,89 @@
1
+ # @monque/core
2
+
3
+ ## 1.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#92](https://github.com/ueberBrot/monque/pull/92) [`e90bdb1`](https://github.com/ueberBrot/monque/commit/e90bdb1ef848398d08346e5bf165d146a8d710b5) Thanks [@ueberBrot](https://github.com/ueberBrot)! - Remove ts-reset global type leakage from published source to prevent dependency errors and unintended global type changes in consumer projects.
8
+
9
+ ## 1.1.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [#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.
14
+
15
+ ## 1.1.0
16
+
17
+ ### Minor Changes
18
+
19
+ - [#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:
20
+
21
+ - **Single Job Management**: `cancelJob`, `retryJob`, `rescheduleJob`, `deleteJob`
22
+ - **Bulk Operations**: `cancelJobs`, `retryJobs`, `deleteJobs` with rich filtering
23
+ - **Cursor Pagination**: `getJobsWithCursor` for stable, efficient iteration over large datasets
24
+ - **Statistics**: `getQueueStats` for monitoring queue health and performance
25
+
26
+ **Events**: New events for observability include `job:cancelled`, `job:retried`, and `job:deleted`.
27
+
28
+ ## 1.0.0
29
+
30
+ ### Major Changes
31
+
32
+ - [#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
33
+
34
+ ## 0.3.0
35
+
36
+ ### Minor Changes
37
+
38
+ - [#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
39
+
40
+ - @monque/core: cron-parser (^5.4.0 → ^5.5.0)
41
+
42
+ ## 0.2.0
43
+
44
+ ### Minor Changes
45
+
46
+ - [#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()`
47
+
48
+ The public method for registering job handlers has been renamed from `worker()` to `register()` for improved API clarity.
49
+
50
+ **Before:**
51
+
52
+ ```typescript
53
+ monque.worker("send-email", async (job) => {
54
+ await sendEmail(job.data);
55
+ });
56
+ ```
57
+
58
+ **After:**
59
+
60
+ ```typescript
61
+ monque.register("send-email", async (job) => {
62
+ await sendEmail(job.data);
63
+ });
64
+ ```
65
+
66
+ This is a **breaking change** for users upgrading from earlier versions. Update all `monque.worker()` calls to `monque.register()`.
67
+
68
+ - [#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
69
+
70
+ This release updates the `engines.node` requirement in `package.json` to `>=22.0.0`.
71
+
72
+ **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.
73
+
74
+ ### Patch Changes
75
+
76
+ - [#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.
77
+
78
+ ## 0.1.0
79
+
80
+ ### Minor Changes
81
+
82
+ - [`fe193bb`](https://github.com/ueberBrot/monque/commit/fe193bb3d840667dded3c3ea093a464d3b1852ba) Thanks [@ueberBrot](https://github.com/ueberBrot)! - Initial pre-release of Monque core.
83
+
84
+ - MongoDB-backed scheduler with atomic claiming/locking to prevent duplicate processing across multiple instances.
85
+ - Workers + concurrency controls for background job processing.
86
+ - Enqueue immediate jobs and schedule recurring jobs via 5-field cron expressions.
87
+ - Built-in retries with configurable exponential backoff.
88
+ - Heartbeats, stale job detection, and recovery on startup.
89
+ - 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
package/dist/index.cjs CHANGED
@@ -1671,7 +1671,7 @@ var JobScheduler = class {
1671
1671
  if (options.uniqueKey) job.uniqueKey = options.uniqueKey;
1672
1672
  try {
1673
1673
  if (options.uniqueKey) {
1674
- const result$1 = await this.ctx.collection.findOneAndUpdate({
1674
+ const result = await this.ctx.collection.findOneAndUpdate({
1675
1675
  name,
1676
1676
  uniqueKey: options.uniqueKey,
1677
1677
  status: { $in: [JobStatus.PENDING, JobStatus.PROCESSING] }
@@ -1679,8 +1679,8 @@ var JobScheduler = class {
1679
1679
  upsert: true,
1680
1680
  returnDocument: "after"
1681
1681
  });
1682
- if (!result$1) throw new ConnectionError("Failed to enqueue job: findOneAndUpdate returned no document");
1683
- return this.ctx.documentToPersistedJob(result$1);
1682
+ if (!result) throw new ConnectionError("Failed to enqueue job: findOneAndUpdate returned no document");
1683
+ return this.ctx.documentToPersistedJob(result);
1684
1684
  }
1685
1685
  const result = await this.ctx.collection.insertOne(job);
1686
1686
  return {
@@ -1783,7 +1783,7 @@ var JobScheduler = class {
1783
1783
  if (options.uniqueKey) job.uniqueKey = options.uniqueKey;
1784
1784
  try {
1785
1785
  if (options.uniqueKey) {
1786
- const result$1 = await this.ctx.collection.findOneAndUpdate({
1786
+ const result = await this.ctx.collection.findOneAndUpdate({
1787
1787
  name,
1788
1788
  uniqueKey: options.uniqueKey,
1789
1789
  status: { $in: [JobStatus.PENDING, JobStatus.PROCESSING] }
@@ -1791,8 +1791,8 @@ var JobScheduler = class {
1791
1791
  upsert: true,
1792
1792
  returnDocument: "after"
1793
1793
  });
1794
- if (!result$1) throw new ConnectionError("Failed to schedule job: findOneAndUpdate returned no document");
1795
- return this.ctx.documentToPersistedJob(result$1);
1794
+ if (!result) throw new ConnectionError("Failed to schedule job: findOneAndUpdate returned no document");
1795
+ return this.ctx.documentToPersistedJob(result);
1796
1796
  }
1797
1797
  const result = await this.ctx.collection.insertOne(job);
1798
1798
  return {