Skip to content

feat(queue): migrate to BullMQ 6, ioredis 6 and latest tooling - #95

Merged
msalvatti merged 3 commits into
mainfrom
feat/support-bullmq-6
Aug 10, 2026
Merged

feat(queue): migrate to BullMQ 6, ioredis 6 and latest tooling#95
msalvatti merged 3 commits into
mainfrom
feat/support-bullmq-6

Conversation

@msalvatti

Copy link
Copy Markdown
Member

Summary

Clean migration of @bymax-one/nest-queue to the newest majors of its Redis/BullMQ stack, released
as 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

  • Peers → newest majors: 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 JobStatus union, JOB_STATUS, getMetrics().counts, and CleanableStatus. The
    queue-lifecycle events 'paused'/'resumed' (@OnQueueEvent) and pauseQueue/resumeQueue
    are unchanged — those describe the queue, not a job.
  • ioredis 6 RESP3 typing fix in connection-resolver.service.ts: a derived options type
    reconstructs the constructor's non-undefined replyMapping requirement (no any, no
    suppression). ioredis 6 keeps 'legacy' reply mapping by default, so getJobCounts/clean/getJobs
    reply shapes are unaffected.
  • Dev tooling: eslint ^10, typescript ^6, @types/node ^26, @eslint/js ^10.
  • Mutation gate tightened: Stryker break/high 95/99 → 100.
  • Docs: README + technical_specification.md updated 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 from
JobStatus, JOB_STATUS, and getMetrics().counts. Shipped as a minor by choice — the changes
would 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:all100% 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

  • TypeScript 7 is held at 6.0.3 on purpose. ts-jest peer is >=4.3 <7 and the whole
    test/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.yaml waives the release-age soak for bullmq@6.0.10 (a fresh major) via
    minimumReleaseAgeExclude, to adopt it now.
  • Independently audited (fresh-context agent, against the official BullMQ v6 docs): no blockers;
    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.
  • Known pre-existing carve-out: Stryker's mutate glob excludes src/server/decorators/**
    (line/branch-covered but not mutation-tested). Not touched by this migration; flagged for a
    possible follow-up.

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.
Copilot AI balanced review requested due to automatic review settings August 10, 2026 22:14
@socket-security

socket-security Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedbullmq-otel@​2.0.01001007189100
Added@​types/​node@​26.2.01001008196100
Addedtypescript@​6.0.31001009010090
Added@​eslint/​js@​10.0.110010010091100
Updatedioredis@​5.11.1 ⏵ 6.0.09410010095100
Addedbullmq@​6.0.109410010096100
Addedeslint@​10.8.19710010097100

View full report

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 paused job 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.

Comment thread package.json
Comment thread pnpm-workspace.yaml
Comment thread pnpm-workspace.yaml
Comment thread scripts/check-published-surface.mjs Outdated
Comment thread tsconfig.build.json Outdated
Comment thread src/server/services/queue.service.ts Outdated
Comment thread test/types/public-api.test-d.ts
Comment thread docs/technical_specification.md Outdated
- 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.
Copilot AI review requested due to automatic review settings August 10, 2026 22:25
@msalvatti

msalvatti commented Aug 10, 2026

Copy link
Copy Markdown
Member Author
{ "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." }

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_OPTIONS in src/server/bymax-queue.constants.ts:7). Configure ConfigurableModuleBuilder with a Symbol-valued optionsInjectionToken and 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')

Comment thread docs/technical_specification.md Outdated
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.
Copilot AI review requested due to automatic review settings August 10, 2026 22:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 JobState also includes prioritized and waiting-children. Omitting them means getJobs cannot 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 update JOB_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 prioritized and waiting-children counts. Priority jobs are supported by enqueue, and flow parents can remain in waiting-children, so getMetrics() underreports queue depth for supported workloads. Request both states and expose them in QueueMetrics.
      '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. ConfigurableModuleBuilder accepts optionsInjectionToken, so configure it with BYMAX_QUEUE_OPTIONS and 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')

@msalvatti
msalvatti merged commit ebfc0ad into main Aug 10, 2026
20 checks passed
@msalvatti
msalvatti deleted the feat/support-bullmq-6 branch August 10, 2026 22:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants