fix(worker): harden the failure paths of watching for work · boringnode/queue@5f9360b · GitHub
Skip to content

Commit 5f9360b

Browse files
committed
fix(worker): harden the failure paths of watching for work
Four failure paths escaped the fallback to polling: - The PostgreSQL probe armed its 2s timeout before its connection completed. A probe connection that stalled left the rejection unobserved, and Node exited instead of falling back to polling. - Aborting a Redis watch only disconnected the blocking client. A PING queued during a silent handshake never settled, so stopping the worker hung. Abort now rejects the PING. - A notification whose payload parsed to null threw in the pg event handler. Any role that can connect can send one, and it killed the worker. Payloads that are not objects are now ignored. - The LISTEN connection did not apply the Knex searchPath, so its announcement queries failed for unqualified tables found only through it. It now sets the search path as the pool does.
1 parent df34750 commit 5f9360b

4 files changed

Lines changed: 94 additions & 8 deletions

File tree

‎src/drivers/knex_adapter.ts‎

Lines changed: 12 additions & 5 deletions

‎src/drivers/redis_adapter.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,14 @@ export class RedisAdapter implements Adapter {
123123
blocking.on('error', (error) => {
124124
this.#logger.error({ err: error }, 'Redis blocking connection error')
125125
})
126-
const abort = () => blocking.disconnect()
126+
// A PING queued during a silent handshake never settles: abort rejects.
127+
const aborted = Promise.withResolvers<never>()
128+
aborted.promise.catch(() => {})
129+
const abort = () => aborted.reject(signal!.reason)
127130
signal?.addEventListener('abort', abort, { once: true })
128131

129132
try {
130-
await blocking.ping()
133+
await Promise.race([blocking.ping(), aborted.promise])
131134
const seedKeys = queues.flatMap((queue) => {
132135
const keys = this.#getKeys(queue)
133136
return [keys.pending, keys.delayed, keys.marker]

‎src/drivers/wake_messages.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ export function dispatchWakeMessage(
3434
onWake: WakeListener,
3535
onSchedule: WakeListener
3636
): void {
37-
let message: Partial<{ ready: unknown; due: unknown; schedule: unknown }>
37+
let message: Partial<{ ready: unknown; due: unknown; schedule: unknown }> | null
3838

3939
try {
4040
message = JSON.parse(raw)
4141
} catch {
4242
return
4343
}
44+
// Any role allowed to connect can notify the channel, with any payload.
45+
if (!message || typeof message !== 'object') return
4446

4547
if (typeof message.schedule === 'number') {
4648
onSchedule(message.schedule)

‎tests/adapter.spec.ts‎

Lines changed: 74 additions & 0 deletions

0 commit comments

Comments
 (0)