Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): lock graph creation when running in another process #29408

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

AgentEnder
Copy link
Member

Current Behavior

Running Nx in multiple processes at the same time with the daemon disabled can cripple a system due to excess memory usage when creating the graph. This is due to plugin workers being started per-parent process when there is no daemon. This change enables a file lock to prevent the simultaneous processing, and read from the cache when the first run completes.

Currently, running nx show projects 30 times in parallel looks something like this:

30 processes exited within 37535ms

Expected Behavior

30 processes exited within 6435ms

Test Script

//@ts-check

const { spawn } = require('child_process');

let alive = new Set();

let start = Date.now();
let iterations = 30;

for (let i = 0; i < iterations; i++) {
  const cp = spawn('npx nx show projects', [], {
    shell: true,
    env: {
      ...process.env,
      NX_DAEMON: 'false',
      NX_VERBOSE_LOGGING: 'true',
    },
  });
  alive.add(i);
  //   cp.stdout.on('data', (data) => {
  //     console.log(`stdout [${i}]: ${data}`);
  //   });
  cp.stderr.on('data', (data) => {
    console.error(`stderr [${i}]: ${data}`);
  });
  cp.on('exit', (code) => {
    console.log(`child process ${i} exited with code ${code}`);
    alive.delete(i);
  });
}

const i = setInterval(() => {
  if (alive.size > 0) {
  } else {
    clearInterval(i);
    console.log(
      `${iterations} processes exited within ${Date.now() - start}ms`
    );
  }
}, 1);

@AgentEnder AgentEnder requested a review from a team as a code owner December 18, 2024 22:33
@AgentEnder AgentEnder requested a review from xiongemi December 18, 2024 22:33
Copy link

vercel bot commented Dec 18, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
nx-dev ✅ Ready (Inspect) Visit Preview Jan 17, 2025 10:09pm

Copy link

nx-cloud bot commented Dec 18, 2024

View your CI Pipeline Execution ↗ for commit 78836c3.

Command Status Duration Result
nx affected --targets=lint,test,build,e2e,e2e-c... ❌ Failed 56m 1s View ↗
nx run-many -t check-imports check-commit check... ✅ Succeeded 16s View ↗
nx-cloud record -- nx-cloud conformance:check ✅ Succeeded 2s View ↗
nx-cloud record -- nx format:check --base=ee135... ✅ Succeeded 2s View ↗
nx-cloud record -- nx sync:check ✅ Succeeded <1s View ↗
nx documentation --no-dte ✅ Succeeded <1s View ↗

☁️ Nx Cloud last updated this comment at 2025-01-18 00:04:06 UTC

@AgentEnder AgentEnder force-pushed the file-lock-graph branch 2 times, most recently from d1f6a60 to 8bb1c07 Compare December 19, 2024 16:14
@@ -290,6 +316,7 @@ export async function createProjectGraphAndSourceMapsAsync(
'create-project-graph-async:start',
'create-project-graph-async:end'
);
lock.unlock();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in a finally at least

packages/nx/src/utils/file-lock.ts Outdated Show resolved Hide resolved
}

wait(timeout?: number) {
return new Promise<void>((res, rej) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use polling

@AgentEnder AgentEnder requested a review from a team as a code owner December 19, 2024 20:16
@AgentEnder AgentEnder requested a review from Cammisuli December 19, 2024 20:16
packages/nx/src/native/utils/file_lock.rs Show resolved Hide resolved
packages/nx/src/native/utils/file_lock.rs Outdated Show resolved Hide resolved
packages/nx/src/project-graph/project-graph.ts Outdated Show resolved Hide resolved
packages/nx/src/project-graph/project-graph.ts Outdated Show resolved Hide resolved
@AgentEnder AgentEnder requested a review from vsavkin as a code owner December 19, 2024 23:20
@AgentEnder AgentEnder force-pushed the file-lock-graph branch 3 times, most recently from 0204e02 to beff91a Compare January 15, 2025 17:56
@AgentEnder AgentEnder requested review from a team as code owners January 15, 2025 18:06
@AgentEnder AgentEnder force-pushed the file-lock-graph branch 2 times, most recently from 16db699 to 7c67700 Compare January 16, 2025 19:06
#[napi(constructor)]
pub fn new(lock_file_path: String) -> anyhow::Result<Self> {
// Creates the directory where the lock file will be stored
fs::create_dir_all(Path::new(&lock_file_path).parent().unwrap())?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't unwrap this. Use ? to return the Err

import { fork } from 'child_process';
import { join } from 'path';

describe('withLock', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename

if (graph.errors.length > 0) {
throw new ProjectGraphError(graph.errors, graph, sourceMaps);
}
if (Date.now() - graph.computedAt < 10_000) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get the current time sooner before Nx even starts waiting. The graph will be computing... and should have been written after it has started waiting... This guarantees that it is not old.

Also handle when there is no graph after waiting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants