|
| 1 | +import { setTimeout as sleep } from 'node:timers/promises' |
1 | 2 | import { test } from '@japa/runner' |
2 | 3 | import { Job } from '../src/job.js' |
3 | 4 | import { Locator } from '../src/locator.js' |
4 | 5 | import { QueueManager } from '../src/queue_manager.js' |
5 | 6 | import { sync } from '../src/drivers/sync_adapter.js' |
6 | 7 | import * as errors from '../src/exceptions.js' |
| 8 | +import { MemoryLogger } from './_mocks/memory_logger.js' |
7 | 9 |
|
8 | 10 | test.group('SyncAdapter', (group) => { |
9 | 11 | group.each.teardown(async () => { |
@@ -55,4 +57,64 @@ test.group('SyncAdapter', (group) => { |
55 | 57 | assert.instanceOf(failedError, errors.E_JOB_MAX_ATTEMPTS_REACHED) |
56 | 58 | assert.deepEqual(contextJobIds, Array(contextJobIds.length).fill(jobId)) |
57 | 59 | }) |
| 60 | + |
| 61 | + test('should log delayed sync job failures without unhandled rejections', async ({ |
| 62 | + assert, |
| 63 | + }) => { |
| 64 | + const logger = new MemoryLogger() |
| 65 | + let unhandledError: unknown |
| 66 | + const onUnhandledRejection = (error: unknown) => { |
| 67 | + unhandledError = error |
| 68 | + } |
| 69 | + |
| 70 | + class DelayedFailingSyncJob extends Job<Record<string, never>> { |
| 71 | + async execute() { |
| 72 | + throw new Error('boom') |
| 73 | + } |
| 74 | + |
| 75 | + async failed() { |
| 76 | + throw new Error('failed hook exploded') |
| 77 | + } |
| 78 | + } |
| 79 | + |
| 80 | + process.once('unhandledRejection', onUnhandledRejection) |
| 81 | + |
| 82 | + try { |
| 83 | + await QueueManager.init({ |
| 84 | + default: 'sync', |
| 85 | + adapters: { sync: sync() }, |
| 86 | + logger, |
| 87 | + }) |
| 88 | + |
| 89 | + Locator.register('DelayedFailingSyncJob', DelayedFailingSyncJob) |
| 90 | + |
| 91 | + const adapter = QueueManager.use() |
| 92 | + |
| 93 | + await adapter.pushLaterOn( |
| 94 | + 'default', |
| 95 | + { |
| 96 | + id: 'delayed-sync-job', |
| 97 | + name: 'DelayedFailingSyncJob', |
| 98 | + payload: {}, |
| 99 | + attempts: 0, |
| 100 | + priority: 0, |
| 101 | + }, |
| 102 | + 0 |
| 103 | + ) |
| 104 | + |
| 105 | + await sleep(20) |
| 106 | + } finally { |
| 107 | + process.removeListener('unhandledRejection', onUnhandledRejection) |
| 108 | + } |
| 109 | + |
| 110 | + assert.isUndefined(unhandledError) |
| 111 | + assert.lengthOf(logger.logs, 1) |
| 112 | + assert.equal(logger.logs[0].level, 'error') |
| 113 | + assert.equal(logger.logs[0].message, 'Failed to execute delayed sync job') |
| 114 | + assert.equal(logger.logs[0].obj?.jobId, 'delayed-sync-job') |
| 115 | + assert.equal(logger.logs[0].obj?.jobName, 'DelayedFailingSyncJob') |
| 116 | + assert.equal(logger.logs[0].obj?.queue, 'default') |
| 117 | + assert.instanceOf(logger.logs[0].obj?.err, Error) |
| 118 | + assert.equal((logger.logs[0].obj?.err as Error).message, 'failed hook exploded') |
| 119 | + }) |
58 | 120 | }) |
0 commit comments