fix(router): post ack comment before enqueuing job to eliminate race condition#647
Conversation
nhopeatall
left a comment
There was a problem hiding this comment.
Summary
LGTM — clean fix for a real race condition between job enqueue and ack comment patching.
The restructuring is sound: moving postAck before buildJob/addJob eliminates the race window where a BullMQ worker could dequeue a job before ackCommentId was patched via updateData(). The fix is minimal, consistent across all three adapters (GitHub, Trello, JIRA), and removes the fragile updateData() patch-after-enqueue pattern along with the now-unnecessary jobQueue import.
Key things verified:
- Error resilience preserved: All three adapter
postAckimplementations wrap their logic in try/catch and returnundefinedon failure, so a failed ack never blocks job enqueue. - Job types consistent:
ackCommentIdis embedded in all three job types;ackMessageis correctly included only inGitHubJob(the only type that has that field). - No stale references:
jobQueueandupdateDataare fully removed fromwebhook-processor.ts. - Interface + all implementations updated:
buildJobsignature extended with optionalackResultin the interface and all three adapters. - Tests updated and comprehensive: Call order test flipped to
['postAck', 'addJob'], new test forbuildJobreceivingackResult, new test confirming enqueue proceeds whenpostAckreturnsundefined. - CI passing: All checks green.
The tradeoff (ack latency now on the enqueue critical path) is well justified — a single comment-posting API call is cheap compared to the cost of workers starting without a pre-seeded ack comment.
|
@aaight resolve conflicts |
e10bf95 to
d153774
Compare
|
Conflicts resolved! Rebased onto
All 19 webhook-processor tests pass, typecheck clean, lint clean. |
|
✅ Review complete — APPROVED Clean fix for a real race condition between job enqueue and ack comment posting. The reordering (postAck → buildJob → addJob) eliminates the window where BullMQ could dequeue a job before |
nhopeatall
left a comment
There was a problem hiding this comment.
Summary
LGTM — clean fix for a real race condition between job enqueue and ack comment posting. The reordering (postAck → buildJob → addJob) eliminates the window where BullMQ could dequeue a job before ackCommentId was patched via updateData().
What I verified:
-
Race condition eliminated:
ackResultis now threaded directly intobuildJobas the 5th parameter, so the job payload is complete at enqueue time. No more post-hoc patching viajobQueue.getJob()+updateData(). -
Failure semantics preserved: All three
postAckimplementations (GitHub, Trello, JIRA) have try/catch guards and returnundefinedon failure — they never throw. So movingpostAckbeforeaddJobdoesn't risk blocking job enqueuing on ack failure. -
Minor behavioral change is acceptable: In the new ordering, if
addJobfails (e.g., Redis down), the ack comment is already posted but the job never enqueues. This is a strict improvement over the old race condition and only manifests in rare Redis failure scenarios. -
Interface consistency: The
AckResultparameter is optional in both the interface and all three adapter implementations. Theas number | undefined/as string | undefinedcasts in each adapter correctly narrow the union type fromAckResult.commentIdto match the platform-specific job types. -
ackMessageomission in Trello/JIRA is intentional: OnlyGitHubJobhas anackMessagefield (confirmed inqueue.tsandworker-entry.ts), so Trello and JIRA adapters correctly omit it. -
Cleanup is complete: The
jobQueueimport is removed fromwebhook-processor.ts, and all relatedupdateDatapatching code is gone. No dead references remain. -
Tests cover the key scenarios: ordering assertion (
['postAck', 'addJob']), ackResult threading to buildJob, and graceful handling of undefined ackResult.
Summary
Fixes a race condition where the BullMQ Worker could pick up a job and serialize
job.dataintoJOB_DATAbefore the router patchedackCommentIdviaupdateData(), causing the worker to start without a pre-seeded ack comment.addJob→ (race window) →postAck→updateData()— worker could dequeue during the race windowprocessRouterWebhook()to callpostAckbeforebuildJobandaddJob, soackCommentIdis embedded directly in the job payload at enqueue time — eliminating the race entirelybuildJobmethods now accept an optionalAckResultparameter and embedackCommentId/ackMessagedirectly in the jobupdateData()patch-after-enqueue block and thejobQueueimport fromwebhook-processor.tsTest plan
['postAck', 'addJob']orderbuildJobis called withackResultas 5th argpostAckreturnsundefined(ack failure is non-fatal)Card: https://trello.com/c/VH29Y9mx/190-lets-make-sure-initial-comment-id-is-successfully-passed-from-router-to-worker-on-order-to-work-on-the-same-comment-from-acknowl
🤖 Generated with Claude Code