Skip to content

Commit abfb25d

Browse files
authored
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
1 parent a4169a1 commit abfb25d

File tree

4 files changed

+43
-7
lines changed

4 files changed

+43
-7
lines changed

docs/shared/reference/environment-variables.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ The following environment variables are ones that you can set to change the beha
3232
| NX_LOAD_DOT_ENV_FILES | boolean | If set to 'false', Nx will not load any environment files (e.g. `.local.env`, `.env.local`) |
3333
| 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. |
3434
| NX_PLUGIN_NO_TIMEOUTS | boolean | If set to `true`, plugin operations will not timeout |
35+
| 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. |
3536

3637
Nx will set the following environment variables so they can be accessible within the process even outside of executors and generators.
3738

packages/nx/bin/post-install.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,13 @@ function isMainNxPackage() {
5656
const thisNxPath = require.resolve('nx');
5757
return mainNxPath === thisNxPath;
5858
}
59+
60+
process.on('uncaughtException', (e) => {
61+
logger.verbose(e);
62+
process.exit(0);
63+
});
64+
65+
process.on('unhandledRejection', (e) => {
66+
logger.verbose(e);
67+
process.exit(0);
68+
});

packages/nx/src/daemon/socket-utils.ts

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { unlinkSync } from 'fs';
2-
import { platform } from 'os';
2+
import { platform, tmpdir } from 'os';
33
import { join, resolve } from 'path';
44
import { getDaemonSocketDir, getSocketDir } from './tmp-dir';
55
import { createSerializableError } from '../utils/serializable-error';
@@ -12,21 +12,44 @@ export const isWindows = platform() === 'win32';
1212
* See https://nodejs.org/dist/latest-v14.x/docs/api/net.html#net_identifying_paths_for_ipc_connections for a full breakdown
1313
* of OS differences between Unix domain sockets and named pipes.
1414
*/
15-
export const getFullOsSocketPath = () =>
16-
isWindows
17-
? '\\\\.\\pipe\\nx\\' + resolve(getDaemonSocketDir())
18-
: resolve(getDaemonSocketDir());
15+
export const getFullOsSocketPath = () => {
16+
const path = resolve(getDaemonSocketDir());
17+
18+
assertValidSocketPath(path);
19+
20+
return isWindows ? '\\\\.\\pipe\\nx\\' + path : path;
21+
};
1922

2023
export const getForkedProcessOsSocketPath = (id: string) => {
2124
let path = resolve(join(getSocketDir(), 'fp' + id + '.sock'));
22-
return isWindows ? '\\\\.\\pipe\\nx\\' + resolve(path) : resolve(path);
25+
26+
assertValidSocketPath(path);
27+
28+
return isWindows ? '\\\\.\\pipe\\nx\\' + path : path;
2329
};
2430

2531
export const getPluginOsSocketPath = (id: string) => {
2632
let path = resolve(join(getSocketDir(true), 'plugin' + id + '.sock'));
27-
return isWindows ? '\\\\.\\pipe\\nx\\' + resolve(path) : resolve(path);
33+
34+
assertValidSocketPath(path);
35+
36+
return isWindows ? '\\\\.\\pipe\\nx\\' + path : path;
2837
};
2938

39+
function assertValidSocketPath(path: string) {
40+
if (path.length > 95) {
41+
throw new Error(
42+
[
43+
'Attempted to open socket that exceeds the maximum socket length.',
44+
'',
45+
`Set NX_SOCKET_DIR to a shorter path (e.g. ${
46+
isWindows ? '%TMP%/nx-tmp' : '/tmp/nx-tmp'
47+
}) to avoid this issue.`,
48+
].join('\n')
49+
);
50+
}
51+
}
52+
3053
export function killSocketOrPath(): void {
3154
try {
3255
unlinkSync(getFullOsSocketPath());

packages/nx/src/daemon/tmp-dir.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,11 @@ function socketDirName() {
6161
export function getSocketDir(alreadyUnique = false) {
6262
try {
6363
const dir =
64+
process.env.NX_SOCKET_DIR ??
6465
process.env.NX_DAEMON_SOCKET_DIR ??
6566
(alreadyUnique ? tmpdir : socketDirName());
6667
ensureDirSync(dir);
68+
6769
return dir;
6870
} catch (e) {
6971
return DAEMON_DIR_FOR_CURRENT_WORKSPACE;

0 commit comments

Comments
 (0)