queue-jobs-worker 1.0.0 → 1.0.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/CHANGELOG.md +122 -76
- package/README.md +7 -1
- package/dist/core/worker.d.ts.map +1 -1
- package/dist/index.cjs +8 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/storage/in-memory.adapter.d.ts.map +1 -1
- package/dist/storage/mysql.adapter.d.ts.map +1 -1
- package/dist/storage/postgres.adapter.d.ts.map +1 -1
- package/dist/storage/redis.adapter.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,76 +1,122 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to **queue-jobs-worker** will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
|
-
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
- `
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
**
|
|
60
|
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to **queue-jobs-worker** will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
|
+
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
## [1.0.1] — 2026-08-31
|
|
10
|
+
|
|
11
|
+
### Core
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **`Worker.stop()` — clarified `releaseLock()` behavior in shutdown comment** ([#1](https://github.com/rafidahmed870/queue-jobs-worker/issues/1))
|
|
16
|
+
|
|
17
|
+
The inline comment in `worker.ts` now correctly explains that `releaseLock()`
|
|
18
|
+
sets `lockExpiresAt` to an already-expired timestamp (not null/empty), so
|
|
19
|
+
`recoverStalledJobs()` on any worker will immediately reclaim the job on the
|
|
20
|
+
next stall-check cycle.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
### Events
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- `QueueEventEmitter` — strongly-typed lifecycle event bus shared across all components.
|
|
29
|
+
- Emits events for the full job lifecycle: enqueued, started, completed, failed, retrying, dead, stalled.
|
|
30
|
+
- All event payloads fully typed via `events.types.ts`.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
<!-- Links -->
|
|
35
|
+
[1.0.0]: https://github.com/rafidahmed870/queue-jobs-worker/releases/tag/v1.0.0
|
|
36
|
+
|
|
37
|
+
### Storage
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- **`releaseLock()` leaves jobs permanently stuck in `active` status** ([#1](https://github.com/rafidahmed870/queue-jobs-worker/issues/1))
|
|
42
|
+
|
|
43
|
+
All four adapters were clearing `lockExpiresAt` to `null` / empty string
|
|
44
|
+
while keeping `status` as `"active"`. Because `recoverStalledJobs()` requires
|
|
45
|
+
a non-null, already-expired `lockExpiresAt` to match a stalled job, those
|
|
46
|
+
jobs were silently skipped and could never be reclaimed or retried.
|
|
47
|
+
|
|
48
|
+
- `InMemoryStorageAdapter.releaseLock()` — `lockExpiresAt` now set to `new Date().toISOString()` instead of `null`.
|
|
49
|
+
- `RedisStorageAdapter.releaseLock()` — `lockExpiresAt` hash field now set to the current ISO timestamp instead of `""`.
|
|
50
|
+
- `PostgreSQLStorageAdapter.releaseLock()` — `lock_expires_at` column now set to `NOW()` instead of `NULL`.
|
|
51
|
+
- `MySQLStorageAdapter.releaseLock()` — `lock_expires_at` column now set to `NOW(3)` instead of `NULL`.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## [1.0.0] — 2026-08-29
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
**Core**
|
|
60
|
+
|
|
61
|
+
- `QueueClient` — primary entry point; configures storage, exposes queues, and coordinates lifecycle.
|
|
62
|
+
- `Queue` — independent job stream with per-queue configuration overrides.
|
|
63
|
+
- `Job` — rich wrapper around the raw job data record; passed to user processors.
|
|
64
|
+
- `Worker` — claims and executes jobs with configurable concurrency and graceful shutdown.
|
|
65
|
+
- `QueueEventEmitter` — strongly-typed lifecycle event bus shared across all components.
|
|
66
|
+
|
|
67
|
+
**Job processing**
|
|
68
|
+
|
|
69
|
+
- At-least-once delivery guarantee.
|
|
70
|
+
- Stable job identity preserved across all retries (no duplicate job IDs).
|
|
71
|
+
- Full attempt history stored per job.
|
|
72
|
+
- Per-job processor timeout enforcement.
|
|
73
|
+
- Priority-ordered job claiming (higher priority = claimed first).
|
|
74
|
+
- Delayed and scheduled job support via `schedule.delay` and `schedule.runAt`.
|
|
75
|
+
- Recurring job support via `schedule.cron` field (cron expression stored; recurrence integration point provided).
|
|
76
|
+
|
|
77
|
+
**Reliability**
|
|
78
|
+
|
|
79
|
+
- Configurable retry with `attempts`, `retryDelay`, and `backoff` strategy.
|
|
80
|
+
- Three backoff strategies: `fixed`, `linear`, `exponential` (capped at 10 minutes).
|
|
81
|
+
- Dead Letter Queue (DLQ): jobs moved to `dead` status after exhausting all attempts.
|
|
82
|
+
- Stalled-job recovery: expired locks on `active` jobs are detected and re-queued automatically.
|
|
83
|
+
- Configurable lock duration (`lockDuration`) per queue.
|
|
84
|
+
|
|
85
|
+
**Concurrency**
|
|
86
|
+
|
|
87
|
+
- Per-worker concurrency limit (`concurrency`).
|
|
88
|
+
- Atomic job claiming inside `InMemoryStorageAdapter` (single event-loop tick).
|
|
89
|
+
|
|
90
|
+
**Rate limiting**
|
|
91
|
+
|
|
92
|
+
- Sliding-window rate limiter configurable per queue (`rateLimit.max` / `rateLimit.duration`).
|
|
93
|
+
|
|
94
|
+
**Storage**
|
|
95
|
+
|
|
96
|
+
- `StorageAdapter` interface — clean abstraction; all core logic talks through this interface.
|
|
97
|
+
- `InMemoryStorageAdapter` — full-featured in-process adapter for development and testing.
|
|
98
|
+
|
|
99
|
+
**Configuration**
|
|
100
|
+
|
|
101
|
+
- Layered configuration: Client defaults → Queue options → Worker options → Job options.
|
|
102
|
+
- `QueueClient.withAdapter()` static factory for supplying a custom storage adapter.
|
|
103
|
+
|
|
104
|
+
**TypeScript**
|
|
105
|
+
|
|
106
|
+
- Full strict TypeScript types with `exactOptionalPropertyTypes` and `noUncheckedIndexedAccess`.
|
|
107
|
+
- All public types exported from the top-level `index.ts`.
|
|
108
|
+
|
|
109
|
+
**Build**
|
|
110
|
+
|
|
111
|
+
- Dual ESM + CJS output via `tsup`.
|
|
112
|
+
- Declaration files (`.d.ts` + `.d.ts.map`) generated via `tsc`.
|
|
113
|
+
|
|
114
|
+
**Tests**
|
|
115
|
+
|
|
116
|
+
- 31 tests across backoff strategies, storage adapter, queue client, and worker behaviour.
|
|
117
|
+
- Coverage: job lifecycle, retry, DLQ, concurrency, stalled recovery, rate limiting, graceful shutdown.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
[1.0.1]: https://github.com/rafidahmed870/queue-jobs-worker/compare/v1.0.0...v1.0.1
|
|
122
|
+
[1.0.0]: https://github.com/rafidahmed870/queue-jobs-worker/releases/tag/v1.0.0
|
package/README.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/core/worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACvF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAI/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,KAAK,gBAAgB,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC;AAyBjD,qBAAa,MAAM;IACjB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;IAC7D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAE1D,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,WAAW,CAAK;IAExB;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAElD,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,YAAY,CAA+B;IAEnD,4DAA4D;IAC5D,OAAO,CAAC,YAAY,CAA6B;gBAG/C,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,iBAAiB,EAC1B,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,EAC3C,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,gBAAgB;IAc5B,IAAI,MAAM,IAAI,YAAY,CAEzB;IAED,8BAA8B;IAC9B,KAAK,IAAI,IAAI;IAab;;;;;;;;OAQG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/core/worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACvF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAI/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,KAAK,gBAAgB,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC;AAyBjD,qBAAa,MAAM;IACjB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;IAC7D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAE1D,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,WAAW,CAAK;IAExB;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAElD,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,YAAY,CAA+B;IAEnD,4DAA4D;IAC5D,OAAO,CAAC,YAAY,CAA6B;gBAG/C,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,iBAAiB,EAC1B,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,EAC3C,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,gBAAgB;IAc5B,IAAI,MAAM,IAAI,YAAY,CAEzB;IAED,8BAA8B;IAC9B,KAAK,IAAI,IAAI;IAab;;;;;;;;OAQG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqD3B,OAAO,CAAC,YAAY;YAQN,IAAI;YAsBJ,SAAS;YAiCT,UAAU;YAwDV,eAAe;YAwDf,aAAa;IA0C3B,OAAO,CAAC,kBAAkB;YAQZ,kBAAkB;CAkBjC"}
|
package/dist/index.cjs
CHANGED
|
@@ -294,10 +294,11 @@ return job_id
|
|
|
294
294
|
// Release lock
|
|
295
295
|
// -------------------------------------------------------------------------
|
|
296
296
|
async releaseLock(jobId) {
|
|
297
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
297
298
|
await this.client.hSet(k.job(jobId), {
|
|
298
299
|
lockId: "",
|
|
299
|
-
lockExpiresAt:
|
|
300
|
-
updatedAt:
|
|
300
|
+
lockExpiresAt: now,
|
|
301
|
+
updatedAt: now
|
|
301
302
|
});
|
|
302
303
|
}
|
|
303
304
|
// -------------------------------------------------------------------------
|
|
@@ -678,7 +679,7 @@ CREATE TABLE IF NOT EXISTS qjw_rate_limits (
|
|
|
678
679
|
async releaseLock(jobId) {
|
|
679
680
|
await this.pool.query(
|
|
680
681
|
`UPDATE qjw_jobs
|
|
681
|
-
SET lock_id = NULL, lock_expires_at =
|
|
682
|
+
SET lock_id = NULL, lock_expires_at = NOW(), updated_at = NOW()
|
|
682
683
|
WHERE id = $1`,
|
|
683
684
|
[jobId]
|
|
684
685
|
);
|
|
@@ -1029,7 +1030,7 @@ CREATE TABLE IF NOT EXISTS qjw_rate_limits (
|
|
|
1029
1030
|
async releaseLock(jobId) {
|
|
1030
1031
|
await this.pool.query(
|
|
1031
1032
|
`UPDATE qjw_jobs
|
|
1032
|
-
SET lock_id = NULL, lock_expires_at =
|
|
1033
|
+
SET lock_id = NULL, lock_expires_at = NOW(3), updated_at = NOW(3)
|
|
1033
1034
|
WHERE id = ?`,
|
|
1034
1035
|
[jobId]
|
|
1035
1036
|
);
|
|
@@ -1904,9 +1905,10 @@ var InMemoryStorageAdapter = class {
|
|
|
1904
1905
|
async releaseLock(jobId) {
|
|
1905
1906
|
const job = this.jobs.get(jobId);
|
|
1906
1907
|
if (!job) return;
|
|
1908
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1907
1909
|
job.lockId = null;
|
|
1908
|
-
job.lockExpiresAt =
|
|
1909
|
-
job.updatedAt =
|
|
1910
|
+
job.lockExpiresAt = now;
|
|
1911
|
+
job.updatedAt = now;
|
|
1910
1912
|
}
|
|
1911
1913
|
// -------------------------------------------------------------------------
|
|
1912
1914
|
// Recover stalled jobs
|