feat(queue): migrate to BullMQ 6, ioredis 6 and latest tooling - #95
Conversation
Clean migration to the newest majors (no consumer yet, so no back-compat ranges), released as 1.2.0. - Peers move to bullmq ^6.0.0, bullmq-otel ^2.0.0, ioredis ^6.0.0. - Remove the 'paused' job state (bullmq 6 dropped it; paused-queue jobs live in 'wait'): gone from the JobStatus union, JOB_STATUS, getMetrics().counts and CleanableStatus. The queue-lifecycle 'paused'/'resumed' events and pauseQueue/resumeQueue are unchanged — those describe the queue, not a job. - Fix the ioredis 6 RESP3 typing on new Redis() with a derived options type (no any, no suppression); ioredis 6 keeps 'legacy' reply mapping by default, so reply shapes are unaffected. - Dev tooling: eslint ^10, typescript ^6 (7 is blocked by ts-jest <7), @types/node ^26. Stryker break raised 95 -> 100 (100% score, 0 survivors). - Docs (README, technical spec) and CHANGELOG updated to BullMQ 6; frozen planning dashboards left as historical snapshots. Shipped as a minor by choice: the changes are breaking but the package has no downstream consumer yet. BREAKING CHANGE: requires bullmq ^6, bullmq-otel ^2, ioredis ^6; the 'paused' job status is removed from JobStatus, JOB_STATUS and getMetrics().counts.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Migrates the library to BullMQ 6, ioredis 6, and updated tooling while releasing version 1.2.0.
Changes:
- Updates Redis/BullMQ peers and developer tooling.
- Removes the obsolete
pausedjob status and updates metrics/types. - Tightens mutation thresholds and refreshes documentation.
Reviewed changes
Copilot reviewed 20 out of 21 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
tsconfig.build.json |
Handles TypeScript 6 deprecation diagnostics. |
test/types/public-api.test-d.ts |
Updates the public status contract. |
stryker.config.json |
Raises mutation thresholds to 100%. |
src/shared/types/queue-metrics.types.ts |
Updates metrics to five statuses. |
src/shared/types/job-status.types.ts |
Removes paused from JobStatus. |
src/shared/constants/job-status.ts |
Removes JOB_STATUS.PAUSED. |
src/shared/constants/job-status.spec.ts |
Updates status constant assertions. |
src/server/services/scheduler-metrics.integration.spec.ts |
Updates mocked metrics. |
src/server/services/queue.service.ts |
Adapts status handling for BullMQ 6. |
src/server/services/queue.service.spec.ts |
Updates queue metrics tests. |
src/server/services/metrics.service.spec.ts |
Updates metrics fixtures. |
src/server/services/connection-resolver.service.ts |
Handles ioredis 6 option typing. |
src/server/bymax-queue.module.ts |
Clarifies generated token behavior. |
src/server/bymax-queue.module.spec.ts |
Pins the generated option token. |
scripts/check-published-surface.mjs |
Supports TypeScript 6 checks. |
README.md |
Documents BullMQ 6 compatibility. |
pnpm-workspace.yaml |
Pins upgraded Redis/BullMQ packages. |
pnpm-lock.yaml |
Resolves upgraded dependencies. |
package.json |
Updates version, peers, and tooling. |
docs/technical_specification.md |
Revises the BullMQ compatibility contract. |
CHANGELOG.md |
Records the 1.2.0 migration. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Restore 'paused' to CleanableStatus: BullMQ 6's Queue.clean() still accepts 'paused' (only JobType, used by getJobCounts/getJobs, dropped it), so removing it from the clean() filter was an over-eager regression. - Remove the unused ioredis-mock devDependency; nothing imports it, and its ioredis ^5 peer clashed with the ioredis 6 override, hiding the mismatch. - consumer-app fixture now declares bullmq ^6 / ioredis ^6 (the workspace override was silently rewriting its ^5 request). - Reword the tsconfig.build.json and check-published-surface.mjs comments to be timeless (drop the future-TypeScript-7 prediction). - Fix the stale "six-member union" comment (now five) in the type test, and refresh the spec header date/revision.
{ "consecutiveFailures": {}, "flakyReruns": {}, "processedCommentIds": [3753837152, 3753837185, 3753837227, 3753837257, 3753837287, 3753837321, 3753837354, 3753837393, 3753892101], "paused": false, "terminated": true, "note": "All 9 Copilot comments resolved (fixes in 64def55 + 40fbe47; 1 semver kept as deliberate 1.2.0). CI green (16 pass, 3 neutral skips) incl. E2E + consumer-app typecheck. Local mutation:full 100%. Re-review settled, no new comments. Ready to merge." } |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 21 out of 22 changed files in this pull request and generated 1 comment.
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
Suppressed comments (1)
src/server/bymax-queue.module.spec.ts:105
- This new assertion codifies a string as a DI token, contrary to the repository's symbol-only token contract (for example,
BYMAX_QUEUE_OPTIONSinsrc/server/bymax-queue.constants.ts:7). ConfigureConfigurableModuleBuilderwith a Symbol-valuedoptionsInjectionTokenand assert that symbol instead; retaining the generated string preserves the silent token-collision risk the convention is intended to prevent.
expect(MODULE_OPTIONS_TOKEN).toBe('BYMAX_QUEUE_MODULE_OPTIONS')
The code's CleanableStatus was corrected back to include 'paused' (BullMQ 6's Queue.clean still accepts it); the spec's cleanQueue signature must match. The job-state removal only affects getJobCounts/getJobs (JobType), which the spec already reflects, and the queue-event 'paused'/'resumed' names are unchanged.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 21 out of 22 changed files in this pull request and generated no new comments.
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
Suppressed comments (3)
src/shared/types/job-status.types.ts:13
- BullMQ 6's
JobStatealso includesprioritizedandwaiting-children. Omitting them meansgetJobscannot query priority jobs (which this service can enqueue) or flow parents waiting on children, despite this type claiming to mirror BullMQ's status set. Add both states and updateJOB_STATUS, metrics, documentation, and contract tests together.
export type JobStatus = 'waiting' | 'active' | 'completed' | 'failed' | 'delayed'
src/server/services/queue.service.ts:228
- This snapshot still omits BullMQ 6's
prioritizedandwaiting-childrencounts. Priority jobs are supported byenqueue, and flow parents can remain inwaiting-children, sogetMetrics()underreports queue depth for supported workloads. Request both states and expose them inQueueMetrics.
'active',
'completed',
'failed',
'delayed',
)
src/server/bymax-queue.module.spec.ts:105
- This assertion enshrines a string-valued DI token, contrary to the repository rule that injection tokens use
Symbol()to avoid silent collisions.ConfigurableModuleBuilderacceptsoptionsInjectionToken, so configure it withBYMAX_QUEUE_OPTIONSand assert symbol identity instead of pinning the generated string (then remove the self-aliasing provider).
it('derives the option token name from the configured module name', () => {
// The `moduleName` handed to the configurable-module builder shapes the generated option
// token's identifier. Pinning the concrete name locks that argument: emptying the module
// name, or dropping the builder's options object entirely, degrades the token to an opaque
// `CONFIGURABLE_MODULE_OPTIONS[<hash>]`, which this exact-match assertion rejects.
expect(MODULE_OPTIONS_TOKEN).toBe('BYMAX_QUEUE_MODULE_OPTIONS')
Summary
Clean migration of
@bymax-one/nest-queueto the newest majors of its Redis/BullMQ stack, releasedas 1.2.0. There is no downstream consumer yet, so the peers move straight to the new majors with
no back-compat ranges. Verified end-to-end and independently audited.
Changes
bullmq ^6.0.0,bullmq-otel ^2.0.0,ioredis ^6.0.0.'paused'job state removed (BullMQ 6 dropped it — paused-queue jobs now live in'wait'):gone from the
JobStatusunion,JOB_STATUS,getMetrics().counts, andCleanableStatus. Thequeue-lifecycle events
'paused'/'resumed'(@OnQueueEvent) andpauseQueue/resumeQueueare unchanged — those describe the queue, not a job.
connection-resolver.service.ts: a derived options typereconstructs the constructor's non-
undefinedreplyMappingrequirement (noany, nosuppression). ioredis 6 keeps
'legacy'reply mapping by default, sogetJobCounts/clean/getJobsreply shapes are unaffected.
eslint ^10,typescript ^6,@types/node ^26,@eslint/js ^10.break/high95/99 → 100.technical_specification.mdupdated to BullMQ 6 (branding, peer tables,install instructions, §14.5 decision, example manifests). CHANGELOG finalized as
[1.2.0].Breaking changes
Requires
bullmq ^6,bullmq-otel ^2,ioredis ^6; the'paused'job status is removed fromJobStatus,JOB_STATUS, andgetMetrics().counts. Shipped as a minor by choice — the changeswould normally warrant a major, but the package has no consumer yet; the CHANGELOG spells out every
breaking detail for a first adopter.
Verification (all green, run locally)
typecheck,test:types,lint(eslint 10),build(tsup),check:exports,check:mutants,check:published— pass.test:cov:all— 100% on all four axes (565/565, 231/231, 126/126, 520/520), 281 tests.mutation:full(cold) — 100.00%, 0 survived, 0 no-coverage,break: 100.Notes for the reviewer
ts-jestpeer is>=4.3 <7and the wholetest/mutation stack runs through it; TS 7 removed the classic compiler API these tools use.
Support returns with ts-jest's TS 7.1 update (~Oct 2026).
pnpm-workspace.yamlwaives the release-age soak forbullmq@6.0.10(a fresh major) viaminimumReleaseAgeExclude, to adopt it now.it independently re-ran every gate and confirmed 100%/100%. The one must-fix it found — stale
BullMQ-5 version strings in README/spec — is fixed in this PR.
mutateglob excludessrc/server/decorators/**(line/branch-covered but not mutation-tested). Not touched by this migration; flagged for a
possible follow-up.