fix(core): handle self shutdown for plugin workers is orphaned before connections and loading
This commit is contained in:
parent
0ae87f191c
commit
1bf0e67e1b
@ -579,6 +579,12 @@ export class DaemonClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async startInBackground(): Promise<ChildProcess['pid']> {
|
async startInBackground(): Promise<ChildProcess['pid']> {
|
||||||
|
if (global.NX_PLUGIN_WORKER) {
|
||||||
|
throw new Error(
|
||||||
|
'Fatal Error: Something unexpected has occurred. Plugin Workers should not start a new daemon process. Please report this issue.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
mkdirSync(DAEMON_DIR_FOR_CURRENT_WORKSPACE, { recursive: true });
|
mkdirSync(DAEMON_DIR_FOR_CURRENT_WORKSPACE, { recursive: true });
|
||||||
if (!existsSync(DAEMON_OUTPUT_LOG_FILE)) {
|
if (!existsSync(DAEMON_OUTPUT_LOG_FILE)) {
|
||||||
writeFileSync(DAEMON_OUTPUT_LOG_FILE, '');
|
writeFileSync(DAEMON_OUTPUT_LOG_FILE, '');
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { PackageJson } from '../../utils/package-json';
|
|||||||
import { nxVersion } from '../../utils/versions';
|
import { nxVersion } from '../../utils/versions';
|
||||||
import { setupWorkspaceContext } from '../../utils/workspace-context';
|
import { setupWorkspaceContext } from '../../utils/workspace-context';
|
||||||
import { workspaceRoot } from '../../utils/workspace-root';
|
import { workspaceRoot } from '../../utils/workspace-root';
|
||||||
import { writeDaemonJsonProcessCache } from '../cache';
|
import { getDaemonProcessIdSync, writeDaemonJsonProcessCache } from '../cache';
|
||||||
import {
|
import {
|
||||||
getFullOsSocketPath,
|
getFullOsSocketPath,
|
||||||
isWindows,
|
isWindows,
|
||||||
@ -518,6 +518,17 @@ export async function startServer(): Promise<Server> {
|
|||||||
server.listen(getFullOsSocketPath(), async () => {
|
server.listen(getFullOsSocketPath(), async () => {
|
||||||
try {
|
try {
|
||||||
serverLogger.log(`Started listening on: ${getFullOsSocketPath()}`);
|
serverLogger.log(`Started listening on: ${getFullOsSocketPath()}`);
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
if (getDaemonProcessIdSync() !== process.pid) {
|
||||||
|
return handleServerProcessTermination({
|
||||||
|
server,
|
||||||
|
reason: 'this process is no longer the current daemon (native)',
|
||||||
|
sockets: openSockets,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).unref();
|
||||||
|
|
||||||
// this triggers the storage of the lock file hash
|
// this triggers the storage of the lock file hash
|
||||||
daemonIsOutdated();
|
daemonIsOutdated();
|
||||||
|
|
||||||
|
|||||||
@ -12,12 +12,23 @@ if (process.env.NX_PERF_LOGGING === 'true') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
global.NX_GRAPH_CREATION = true;
|
global.NX_GRAPH_CREATION = true;
|
||||||
|
global.NX_PLUGIN_WORKER = true;
|
||||||
|
let connected = false;
|
||||||
let plugin: LoadedNxPlugin;
|
let plugin: LoadedNxPlugin;
|
||||||
|
|
||||||
const socketPath = process.argv[2];
|
const socketPath = process.argv[2];
|
||||||
|
|
||||||
const server = createServer((socket) => {
|
const server = createServer((socket) => {
|
||||||
|
connected = true;
|
||||||
|
// This handles cases where the host process was killed
|
||||||
|
// after the worker connected but before the worker was
|
||||||
|
// instructed to load the plugin.
|
||||||
|
const loadTimeout = setTimeout(() => {
|
||||||
|
console.error(
|
||||||
|
`Plugin Worker exited because no plugin was loaded within 10 seconds of starting up.`
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}, 10000).unref();
|
||||||
socket.on(
|
socket.on(
|
||||||
'data',
|
'data',
|
||||||
consumeMessagesFromSocket((raw) => {
|
consumeMessagesFromSocket((raw) => {
|
||||||
@ -27,6 +38,7 @@ const server = createServer((socket) => {
|
|||||||
}
|
}
|
||||||
return consumeMessage(socket, message, {
|
return consumeMessage(socket, message, {
|
||||||
load: async ({ plugin: pluginConfiguration, root }) => {
|
load: async ({ plugin: pluginConfiguration, root }) => {
|
||||||
|
if (loadTimeout) clearTimeout(loadTimeout);
|
||||||
process.chdir(root);
|
process.chdir(root);
|
||||||
try {
|
try {
|
||||||
const [promise] = loadNxPlugin(pluginConfiguration, root);
|
const [promise] = loadNxPlugin(pluginConfiguration, root);
|
||||||
@ -120,6 +132,8 @@ const server = createServer((socket) => {
|
|||||||
// since the worker is spawned per host process. As such,
|
// since the worker is spawned per host process. As such,
|
||||||
// we can safely close the worker when the host disconnects.
|
// we can safely close the worker when the host disconnects.
|
||||||
socket.on('end', () => {
|
socket.on('end', () => {
|
||||||
|
// Destroys the socket once it's fully closed.
|
||||||
|
socket.destroySoon();
|
||||||
// Stops accepting new connections, but existing connections are
|
// Stops accepting new connections, but existing connections are
|
||||||
// not closed immediately.
|
// not closed immediately.
|
||||||
server.close(() => {
|
server.close(() => {
|
||||||
@ -128,13 +142,20 @@ const server = createServer((socket) => {
|
|||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
// Destroys the socket once it's fully closed.
|
|
||||||
socket.destroySoon();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
server.listen(socketPath);
|
server.listen(socketPath);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!connected) {
|
||||||
|
console.error(
|
||||||
|
'The plugin worker is exiting as it was not connected to within 5 seconds.'
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}, 5000).unref();
|
||||||
|
|
||||||
const exitHandler = (exitCode: number) => () => {
|
const exitHandler = (exitCode: number) => () => {
|
||||||
server.close();
|
server.close();
|
||||||
try {
|
try {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user