fix(core): prevent post install failures when socket path too long (#27366)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
We communicate with sockets during graph construction. Its possible for
the assigned path to be too long and this can cause issues. The issues
present as a strange error with no helpful information.

## Expected Behavior
There is a helpful error message, and post-install is not interrupted

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #27040
This commit is contained in:
Craigory Coppola 2024-08-09 23:15:23 -04:00 committed by GitHub
parent a4169a1291
commit abfb25dc37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 43 additions and 7 deletions

View File

@ -32,6 +32,7 @@ The following environment variables are ones that you can set to change the beha
| NX_LOAD_DOT_ENV_FILES | boolean | If set to 'false', Nx will not load any environment files (e.g. `.local.env`, `.env.local`) |
| NX_NATIVE_FILE_CACHE_DIRECTORY | string | The cache for native `.node` files is stored under a global temp directory by default. Set this variable to use a different directory. This is interpreted as an absolute path. |
| NX_PLUGIN_NO_TIMEOUTS | boolean | If set to `true`, plugin operations will not timeout |
| NX_SOCKET_DIRECTORY | string | Sets the directory that Nx will use when creating sockets to communicate with child processes. May be needed if the derived socket path is too long. |
Nx will set the following environment variables so they can be accessible within the process even outside of executors and generators.

View File

@ -56,3 +56,13 @@ function isMainNxPackage() {
const thisNxPath = require.resolve('nx');
return mainNxPath === thisNxPath;
}
process.on('uncaughtException', (e) => {
logger.verbose(e);
process.exit(0);
});
process.on('unhandledRejection', (e) => {
logger.verbose(e);
process.exit(0);
});

View File

@ -1,5 +1,5 @@
import { unlinkSync } from 'fs';
import { platform } from 'os';
import { platform, tmpdir } from 'os';
import { join, resolve } from 'path';
import { getDaemonSocketDir, getSocketDir } from './tmp-dir';
import { createSerializableError } from '../utils/serializable-error';
@ -12,21 +12,44 @@ export const isWindows = platform() === 'win32';
* See https://nodejs.org/dist/latest-v14.x/docs/api/net.html#net_identifying_paths_for_ipc_connections for a full breakdown
* of OS differences between Unix domain sockets and named pipes.
*/
export const getFullOsSocketPath = () =>
isWindows
? '\\\\.\\pipe\\nx\\' + resolve(getDaemonSocketDir())
: resolve(getDaemonSocketDir());
export const getFullOsSocketPath = () => {
const path = resolve(getDaemonSocketDir());
assertValidSocketPath(path);
return isWindows ? '\\\\.\\pipe\\nx\\' + path : path;
};
export const getForkedProcessOsSocketPath = (id: string) => {
let path = resolve(join(getSocketDir(), 'fp' + id + '.sock'));
return isWindows ? '\\\\.\\pipe\\nx\\' + resolve(path) : resolve(path);
assertValidSocketPath(path);
return isWindows ? '\\\\.\\pipe\\nx\\' + path : path;
};
export const getPluginOsSocketPath = (id: string) => {
let path = resolve(join(getSocketDir(true), 'plugin' + id + '.sock'));
return isWindows ? '\\\\.\\pipe\\nx\\' + resolve(path) : resolve(path);
assertValidSocketPath(path);
return isWindows ? '\\\\.\\pipe\\nx\\' + path : path;
};
function assertValidSocketPath(path: string) {
if (path.length > 95) {
throw new Error(
[
'Attempted to open socket that exceeds the maximum socket length.',
'',
`Set NX_SOCKET_DIR to a shorter path (e.g. ${
isWindows ? '%TMP%/nx-tmp' : '/tmp/nx-tmp'
}) to avoid this issue.`,
].join('\n')
);
}
}
export function killSocketOrPath(): void {
try {
unlinkSync(getFullOsSocketPath());

View File

@ -61,9 +61,11 @@ function socketDirName() {
export function getSocketDir(alreadyUnique = false) {
try {
const dir =
process.env.NX_SOCKET_DIR ??
process.env.NX_DAEMON_SOCKET_DIR ??
(alreadyUnique ? tmpdir : socketDirName());
ensureDirSync(dir);
return dir;
} catch (e) {
return DAEMON_DIR_FOR_CURRENT_WORKSPACE;