Skip to content

Commit 9fa56d0

Browse files
committedNov 25, 2024··
fix(core): handle self shutdown for plugin workers is orphaned before connections and loading
(cherry picked from commit 1bf0e67)
1 parent 42ea072 commit 9fa56d0

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed
 

Diff for: ‎packages/nx/src/daemon/client/client.ts

+6
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,12 @@ export class DaemonClient {
582582
}
583583

584584
async startInBackground(): Promise<ChildProcess['pid']> {
585+
if (global.NX_PLUGIN_WORKER) {
586+
throw new Error(
587+
'Fatal Error: Something unexpected has occurred. Plugin Workers should not start a new daemon process. Please report this issue.'
588+
);
589+
}
590+
585591
mkdirSync(DAEMON_DIR_FOR_CURRENT_WORKSPACE, { recursive: true });
586592
if (!existsSync(DAEMON_OUTPUT_LOG_FILE)) {
587593
writeFileSync(DAEMON_OUTPUT_LOG_FILE, '');

Diff for: ‎packages/nx/src/daemon/server/server.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { PackageJson } from '../../utils/package-json';
1010
import { nxVersion } from '../../utils/versions';
1111
import { setupWorkspaceContext } from '../../utils/workspace-context';
1212
import { workspaceRoot } from '../../utils/workspace-root';
13-
import { writeDaemonJsonProcessCache } from '../cache';
13+
import { getDaemonProcessIdSync, writeDaemonJsonProcessCache } from '../cache';
1414
import {
1515
getFullOsSocketPath,
1616
isWindows,
@@ -518,6 +518,17 @@ export async function startServer(): Promise<Server> {
518518
server.listen(getFullOsSocketPath(), async () => {
519519
try {
520520
serverLogger.log(`Started listening on: ${getFullOsSocketPath()}`);
521+
522+
setInterval(() => {
523+
if (getDaemonProcessIdSync() !== process.pid) {
524+
return handleServerProcessTermination({
525+
server,
526+
reason: 'this process is no longer the current daemon (native)',
527+
sockets: openSockets,
528+
});
529+
}
530+
}).unref();
531+
521532
// this triggers the storage of the lock file hash
522533
daemonIsOutdated();
523534

Diff for: ‎packages/nx/src/project-graph/plugins/isolation/plugin-worker.ts

+24-3
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,23 @@ if (process.env.NX_PERF_LOGGING === 'true') {
1212
}
1313

1414
global.NX_GRAPH_CREATION = true;
15-
15+
global.NX_PLUGIN_WORKER = true;
16+
let connected = false;
1617
let plugin: LoadedNxPlugin;
1718

1819
const socketPath = process.argv[2];
1920

2021
const server = createServer((socket) => {
22+
connected = true;
23+
// This handles cases where the host process was killed
24+
// after the worker connected but before the worker was
25+
// instructed to load the plugin.
26+
const loadTimeout = setTimeout(() => {
27+
console.error(
28+
`Plugin Worker exited because no plugin was loaded within 10 seconds of starting up.`
29+
);
30+
process.exit(1);
31+
}, 10000).unref();
2132
socket.on(
2233
'data',
2334
consumeMessagesFromSocket((raw) => {
@@ -27,6 +38,7 @@ const server = createServer((socket) => {
2738
}
2839
return consumeMessage(socket, message, {
2940
load: async ({ plugin: pluginConfiguration, root }) => {
41+
if (loadTimeout) clearTimeout(loadTimeout);
3042
process.chdir(root);
3143
try {
3244
const [promise] = loadNxPlugin(pluginConfiguration, root);
@@ -138,6 +150,8 @@ const server = createServer((socket) => {
138150
// since the worker is spawned per host process. As such,
139151
// we can safely close the worker when the host disconnects.
140152
socket.on('end', () => {
153+
// Destroys the socket once it's fully closed.
154+
socket.destroySoon();
141155
// Stops accepting new connections, but existing connections are
142156
// not closed immediately.
143157
server.close(() => {
@@ -146,13 +160,20 @@ const server = createServer((socket) => {
146160
} catch (e) {}
147161
process.exit(0);
148162
});
149-
// Destroys the socket once it's fully closed.
150-
socket.destroySoon();
151163
});
152164
});
153165

154166
server.listen(socketPath);
155167

168+
setTimeout(() => {
169+
if (!connected) {
170+
console.error(
171+
'The plugin worker is exiting as it was not connected to within 5 seconds.'
172+
);
173+
process.exit(1);
174+
}
175+
}, 5000).unref();
176+
156177
const exitHandler = (exitCode: number) => () => {
157178
server.close();
158179
try {

0 commit comments

Comments
 (0)
Please sign in to comment.