Skip to content

Commit 89aa25e

Browse files
authored
fix(core): resolve daemon client reconnect queue deadlock (#34284)
## Current Behavior When the daemon dies while processing a request, the reconnect logic adds the retry back to the promise-based queue. However, the original request is still blocked in the queue waiting for a response that will never come (the socket is dead). This creates a deadlock: 1. Original request (`fn1`) is blocked awaiting a promise that will never resolve 2. Retry request (`fn2`) is queued but can't execute until `fn1` completes 3. `fn1` can't complete because it's waiting on the dead socket ## Expected Behavior When reconnecting after daemon death, the retry should resolve the pending promise that the original queue entry is waiting on, allowing the queue to proceed normally. ## Related Issue(s) <!-- No specific issue, discovered during development --> ## Solution Instead of re-queuing the retry through `sendToDaemonViaQueue` (which adds to the end of the queue), we now call `sendMessageToDaemon` directly. This resolves the pending promise that `fn1` is waiting on, allowing it to complete naturally and the queue to proceed. Also removed the now-unused `decrementQueueCounter` method from `PromisedBasedQueue`.
1 parent cdd735d commit 89aa25e

2 files changed

Lines changed: 4 additions & 14 deletions

File tree

packages/nx/src/daemon/client/client.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,13 +1113,13 @@ export class DaemonClient {
11131113

11141114
// Resend the pending message if one exists
11151115
if (this.currentMessage && this.currentResolve && this.currentReject) {
1116-
// Decrement the queue counter that was incremented when the error occurred
1117-
this.queue.decrementQueueCounter();
1118-
// Retry the message through the normal queue
1116+
// Retry the message directly (not through the queue) to resolve the
1117+
// pending promise that the original queue entry is waiting on.
1118+
// This allows the original queue entry to complete naturally.
11191119
const msg = this.currentMessage;
11201120
const res = this.currentResolve;
11211121
const rej = this.currentReject;
1122-
this.sendToDaemonViaQueue(msg).then(res, rej);
1122+
this.sendMessageToDaemon(msg).then(res, rej);
11231123
}
11241124
} else {
11251125
// Failed to reconnect after all attempts, reject the pending request

packages/nx/src/utils/promised-based-queue.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,4 @@ export class PromisedBasedQueue {
3535
isEmpty() {
3636
return this.counter === 0;
3737
}
38-
39-
/**
40-
* Used to decrement the internal counter representing the number of active promises in the queue.
41-
* This is useful for retrying a failed daemon message, as we want to be able to shut the daemon down
42-
* without marking the promise that represents the failed message as settled. To do so, we store
43-
* the promise in a separate variable and only resolve or reject it later.
44-
*/
45-
decrementQueueCounter() {
46-
this.counter--;
47-
}
4838
}

0 commit comments

Comments
 (0)