feat: add .id() method for job deduplication#12
feat: add .id() method for job deduplication#12jigs1996 wants to merge 3 commits intoboringnode:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an optional JobDispatcher.id() builder to enable job deduplication by using a custom ID (auto-prefixed with the job name) and a new unique flag that adapters interpret as “insert-if-not-exists”.
Changes:
- Introduces
JobDispatcher.id()and setsJobData.uniquewhen a custom ID is used. - Implements adapter-level dedup behavior for Redis (Lua +
HSETNX) and Knex (ON CONFLICT DO NOTHING), plus in-memory fakes. - Adds test coverage for custom IDs and unique-push behavior, and documents the feature in the README.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/job_dispatcher.spec.ts | Adds tests for .id() behavior (validation, prefixing, unique flag, dedup). |
| tests/fake_adapter.spec.ts | Adds tests ensuring FakeAdapter skips duplicate pushes when unique is set. |
| tests/_utils/register_driver_test_suite.ts | Extends shared driver suite to test unique/dedup semantics across adapters. |
| tests/_mocks/memory_adapter.ts | Adds unique existence checks for the in-test memory adapter. |
| src/types/main.ts | Adds unique?: boolean to JobData with explanatory docs. |
| src/job_dispatcher.ts | Adds .id() builder and wires prefixed IDs + unique flag into dispatched job data. |
| src/drivers/redis_adapter.ts | Adds Lua scripts to atomically skip duplicates for unique jobs (immediate and delayed). |
| src/drivers/knex_adapter.ts | Uses onConflict(['id','queue']).ignore() when unique is set. |
| src/drivers/fake_adapter.ts | Adds unique existence checks before enqueueing/scheduling fake jobs. |
| README.md | Documents job deduplication via .id() and its interaction with retention. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Just a quick thought,what about this API instead : await SendInvoiceJob
.dispatch({ orderId: 123 })
.dedup({ id: 'order-124' })
.run()That would make the API easier to extend later if we want to support more advanced deduplication modes, similar to BullMQ, for example TTL-based deduplication, replace/debounce behavior, or other options. SEe https://docs.bullmq.io/guide/jobs/deduplication For example later we could have : await SendInvoiceJob
.dispatch({ orderId: 123 })
.dedup({
id: 'order-123',
ttl: '5s',
})
.run() |
|
That’s a good idea. I’ll take this up on Saturday. |
422a360 to
eda02cf
Compare
eda02cf to
69c0635
Compare
Summary
.id()builder method toJobDispatcherfor preventing duplicate jobs.id()throws a clear errorHow it works
Without
.id(), behavior is completely unchanged — jobs use auto-generated UUIDs as before.Adapter implementations
HSETNX+ conditionalZADDvia Lua scriptINSERT ... ON CONFLICT (id, queue) DO NOTHINGBreaking changes
None. All changes are additive and opt-in:
unique?: booleanis an optional field onJobData.id()is a new method — existing code is unaffected(id, queue)primary key)