diff --git a/packages/nx/src/hasher/hash-task.ts b/packages/nx/src/hasher/hash-task.ts index 26e755f537fb4..07ca1fd53e4b5 100644 --- a/packages/nx/src/hasher/hash-task.ts +++ b/packages/nx/src/hasher/hash-task.ts @@ -122,3 +122,81 @@ export async function hashTask( 'hashSingleTask:end' ); } + +export async function hashTasks( + hasher: TaskHasher, + projectGraph: ProjectGraph, + taskGraph: TaskGraph, + env: NodeJS.ProcessEnv, + taskDetails: TaskDetails | null +) { + performance.mark('hashMultipleTasks:start'); + + const projectsConfigurations = + readProjectsConfigurationFromProjectGraph(projectGraph); + const nxJson = readNxJson(); + + const tasks = Object.values(taskGraph.tasks).filter((task) => !task.hash); + + // Separate tasks with custom hashers from those without + const tasksWithCustomHashers: Task[] = []; + const tasksWithoutCustomHashers: Task[] = []; + + for (const task of tasks) { + const customHasher = getCustomHasher(task, projectGraph); + if (customHasher) { + tasksWithCustomHashers.push(task); + } else { + tasksWithoutCustomHashers.push(task); + } + } + + // Hash tasks with custom hashers individually + const customHasherPromises = tasksWithCustomHashers.map(async (task) => { + const customHasher = getCustomHasher(task, projectGraph); + const { value, details } = await customHasher(task, { + hasher, + projectGraph, + taskGraph, + workspaceConfig: projectsConfigurations, + projectsConfigurations, + nxJsonConfiguration: nxJson, + env, + } as any); + task.hash = value; + task.hashDetails = details; + }); + + // Hash tasks without custom hashers in batch + let batchHashPromise: Promise = Promise.resolve(); + if (tasksWithoutCustomHashers.length > 0) { + batchHashPromise = hasher + .hashTasks(tasksWithoutCustomHashers, taskGraph, env) + .then((hashes) => { + for (let i = 0; i < tasksWithoutCustomHashers.length; i++) { + tasksWithoutCustomHashers[i].hash = hashes[i].value; + tasksWithoutCustomHashers[i].hashDetails = hashes[i].details; + } + }); + } + + await Promise.all([...customHasherPromises, batchHashPromise]); + + if (taskDetails?.recordTaskDetails) { + taskDetails.recordTaskDetails( + tasks.map((task) => ({ + hash: task.hash, + project: task.target.project, + target: task.target.target, + configuration: task.target.configuration, + })) + ); + } + + performance.mark('hashMultipleTasks:end'); + performance.measure( + 'hashMultipleTasks', + 'hashMultipleTasks:start', + 'hashMultipleTasks:end' + ); +} diff --git a/packages/nx/src/tasks-runner/task-orchestrator.ts b/packages/nx/src/tasks-runner/task-orchestrator.ts index 128bd8c644c39..3f53707c90e35 100644 --- a/packages/nx/src/tasks-runner/task-orchestrator.ts +++ b/packages/nx/src/tasks-runner/task-orchestrator.ts @@ -7,7 +7,7 @@ import { ProjectGraph } from '../config/project-graph'; import { Task, TaskGraph } from '../config/task-graph'; import { DaemonClient } from '../daemon/client/client'; import { runCommands } from '../executors/run-commands/run-commands.impl'; -import { getTaskDetails, hashTask } from '../hasher/hash-task'; +import { getTaskDetails, hashTask, hashTasks } from '../hasher/hash-task'; import { TaskHasher } from '../hasher/task-hasher'; import { IS_WASM, @@ -244,20 +244,18 @@ export class TaskOrchestrator { } private async processScheduledBatch(batch: Batch) { + await hashTasks( + this.hasher, + this.projectGraph, + batch.taskGraph, + this.batchEnv, + this.taskDetails + ); + await Promise.all( - Object.values(batch.taskGraph.tasks).map(async (task) => { - if (!task.hash) { - await hashTask( - this.hasher, - this.projectGraph, - this.taskGraphForHashing, - task, - this.batchEnv, - this.taskDetails - ); - } - await this.options.lifeCycle.scheduleTask(task); - }) + Object.values(batch.taskGraph.tasks).map((task) => + this.options.lifeCycle.scheduleTask(task) + ) ); }