Skip to content

Commit 03afe37

Browse files
authored
Merge pull request #764 from bcomnes/corelate-wip-to-worker
Add workId to localConcurrency workers and WIP data
2 parents 77ec0ea + 5784e38 commit 03afe37

5 files changed

Lines changed: 46 additions & 4 deletions

File tree

docs/api/events.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Emitted at most once every 2 seconds when workers are receiving jobs. The payloa
6363
[
6464
{
6565
id: 'fc738fb0-1de5-4947-b138-40d6a790749e',
66+
workId: 'a1b2c3d4-5678-90ab-cdef-1234567890ab',
6667
name: 'my-queue',
6768
options: { pollingInterval: 2000 },
6869
state: 'active',
@@ -78,6 +79,19 @@ Emitted at most once every 2 seconds when workers are receiving jobs. The payloa
7879
]
7980
```
8081

82+
`workId` is the value returned by `work()`. When using `localConcurrency`, multiple worker entries in the array will share the same `workId`, allowing you to correlate them back to a specific `work()` call.
83+
84+
```js
85+
const workId = await boss.work('my-queue', { localConcurrency: 5 }, handler)
86+
87+
boss.on('wip', workers => {
88+
const myWorkers = workers.filter(w => w.workId === workId)
89+
const working = myWorkers.filter(w => w.count > 0).length
90+
const idle = myWorkers.length - working
91+
console.log(`working: ${working}/${myWorkers.length}, idle: ${idle}`)
92+
})
93+
```
94+
8195
## `stopped`
8296

8397
Emitted after `stop()` once all workers have completed their work and maintenance has been shut down.

src/manager.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ class Manager extends EventEmitter implements types.EventsMixin {
350350

351351
const firstWorkerId = randomUUID({ disableEntropyCache: true })
352352

353-
const createWorker = (workerId: string) => {
353+
const createWorker = (workerId: string, workId: string) => {
354354
const fetch = () => {
355355
const ignoreGroups = localGroupConcurrency != null
356356
? this.#getGroupsAtLocalCapacity(name)
@@ -395,13 +395,13 @@ class Manager extends EventEmitter implements types.EventsMixin {
395395
this.emit(events.error, { ...error, message: error.message, stack: error.stack, queue: name, worker: workerId })
396396
}
397397

398-
return new Worker<ReqData>({ id: workerId, name, options, interval, fetch, onFetch, onError })
398+
return new Worker<ReqData>({ id: workerId, workId, name, options, interval, fetch, onFetch, onError })
399399
}
400400

401401
// Spawn workers based on localConcurrency setting
402402
for (let i = 0; i < localConcurrency; i++) {
403403
const workerId = i === 0 ? firstWorkerId : randomUUID({ disableEntropyCache: true })
404-
const worker = createWorker(workerId)
404+
const worker = createWorker(workerId, firstWorkerId)
405405

406406
this.addWorker(worker)
407407
worker.start()

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ export type WorkerState = 'created' | 'active' | 'stopping' | 'stopped'
440440

441441
export interface WipData {
442442
id: string;
443+
workId: string;
443444
name: string;
444445
options: WorkOptions;
445446
state: WorkerState;

src/worker.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const WORKER_STATES = {
1010

1111
interface WorkerOptions<T> {
1212
id: string
13+
workId: string
1314
name: string
1415
options: types.WorkOptions
1516
interval: number
@@ -20,6 +21,7 @@ interface WorkerOptions<T> {
2021

2122
class Worker<T = unknown> {
2223
readonly id: string
24+
readonly workId: string
2325
readonly name: string
2426
readonly options: types.WorkOptions
2527
readonly fetch: () => Promise<types.Job<T>[]>
@@ -43,8 +45,9 @@ class Worker<T = unknown> {
4345
private beenNotified = false
4446
private runPromise: Promise<void> | null = null
4547

46-
constructor ({ id, name, options, interval, fetch, onFetch, onError }: WorkerOptions<T>) {
48+
constructor ({ id, workId, name, options, interval, fetch, onFetch, onError }: WorkerOptions<T>) {
4749
this.id = id
50+
this.workId = workId
4851
this.name = name
4952
this.options = options
5053
this.fetch = fetch
@@ -133,6 +136,7 @@ class Worker<T = unknown> {
133136
toWipData (): types.WipData {
134137
return {
135138
id: this.id,
139+
workId: this.workId,
136140
name: this.name,
137141
options: this.options,
138142
state: this.state,

test/workTest.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,29 @@ describe('work', function () {
328328
expect(wip2.length).toBe(1)
329329
})
330330

331+
it('should correlate wip entries to work() call via workId', async function () {
332+
ctx.boss = await helper.start(ctx.bossConfig)
333+
334+
const firstWipEvent = new Promise<Array<any>>(resolve => ctx.boss!.once('wip', resolve))
335+
336+
let handlerCompletedResolve: () => void
337+
const handlerCompleted = new Promise<void>(resolve => { handlerCompletedResolve = resolve })
338+
339+
await ctx.boss.send(ctx.schema)
340+
341+
const workId = await ctx.boss.work(ctx.schema, { localConcurrency: 3, pollingIntervalSeconds: 1 }, async () => {
342+
handlerCompletedResolve()
343+
await delay(3000)
344+
})
345+
346+
const wip = await firstWipEvent
347+
348+
expect(wip.every((w: any) => w.workId === workId)).toBe(true)
349+
expect(wip.length).toBe(3)
350+
351+
await handlerCompleted
352+
})
353+
331354
it('getWipData() should return current worker state', async function () {
332355
ctx.boss = await helper.start(ctx.bossConfig)
333356

0 commit comments

Comments
 (0)