feat(core): remove old cache records
This commit is contained in:
parent
dddc1b1e6c
commit
f84c55d5aa
@ -4,7 +4,9 @@ import { findWorkspaceRoot } from './find-workspace-root';
|
|||||||
|
|
||||||
const workspace = findWorkspaceRoot(process.cwd());
|
const workspace = findWorkspaceRoot(process.cwd());
|
||||||
|
|
||||||
setUpOutputWatching();
|
if (process.env.NX_TERMINAL_OUTPUT_PATH) {
|
||||||
|
setUpOutputWatching();
|
||||||
|
}
|
||||||
requireCli();
|
requireCli();
|
||||||
|
|
||||||
function requireCli() {
|
function requireCli() {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { join } from 'path';
|
|||||||
import { Hasher } from './hasher';
|
import { Hasher } from './hasher';
|
||||||
import * as fsExtra from 'fs-extra';
|
import * as fsExtra from 'fs-extra';
|
||||||
import { DefaultTasksRunnerOptions } from './tasks-runner-v2';
|
import { DefaultTasksRunnerOptions } from './tasks-runner-v2';
|
||||||
|
import { fork, spawn } from 'child_process';
|
||||||
|
|
||||||
export type CachedResult = { terminalOutput: string; outputsPath: string };
|
export type CachedResult = { terminalOutput: string; outputsPath: string };
|
||||||
export type TaskWithCachedResult = { task: Task; cachedResult: CachedResult };
|
export type TaskWithCachedResult = { task: Task; cachedResult: CachedResult };
|
||||||
@ -40,6 +41,35 @@ export class Cache {
|
|||||||
private readonly options: DefaultTasksRunnerOptions
|
private readonly options: DefaultTasksRunnerOptions
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
removeOldCacheRecords() {
|
||||||
|
/**
|
||||||
|
* Even though spawning a process is fast, we don't want to do it every time
|
||||||
|
* the user runs a command. Instead, we want to do it once in a while.
|
||||||
|
*/
|
||||||
|
const shouldSpawnProcess = Math.floor(Math.random() * 50) === 1;
|
||||||
|
if (shouldSpawnProcess) {
|
||||||
|
const scriptPath = join(
|
||||||
|
this.root,
|
||||||
|
'node_modules',
|
||||||
|
'@nrwl',
|
||||||
|
'workspace',
|
||||||
|
'src',
|
||||||
|
'tasks-runner',
|
||||||
|
'remove-old-cache-records.js'
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
const p = spawn('node', [`"${scriptPath}"`, `"${this.cachePath}"`], {
|
||||||
|
stdio: 'ignore',
|
||||||
|
detached: true
|
||||||
|
});
|
||||||
|
p.unref();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`Unable to start remove-old-cache-records script:`);
|
||||||
|
console.log(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async get(task: Task): Promise<CachedResult> {
|
async get(task: Task): Promise<CachedResult> {
|
||||||
if (!this.cacheConfig.isCacheableTask(task)) return null;
|
if (!this.cacheConfig.isCacheableTask(task)) return null;
|
||||||
|
|
||||||
@ -60,7 +90,6 @@ export class Cache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async put(task: Task, terminalOutputPath: string, folders: string[]) {
|
async put(task: Task, terminalOutputPath: string, folders: string[]) {
|
||||||
if (!this.cacheConfig.isCacheableTask(task)) return;
|
|
||||||
const terminalOutput = readFileSync(terminalOutputPath).toString();
|
const terminalOutput = readFileSync(terminalOutputPath).toString();
|
||||||
const hash = await this.hasher.hash(task);
|
const hash = await this.hasher.hash(task);
|
||||||
const td = join(this.cachePath, hash);
|
const td = join(this.cachePath, hash);
|
||||||
@ -115,7 +144,11 @@ export class Cache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async temporaryOutputPath(task: Task) {
|
async temporaryOutputPath(task: Task) {
|
||||||
return join(this.terminalOutputsDir, await this.hasher.hash(task));
|
if (this.cacheConfig.isCacheableTask(task)) {
|
||||||
|
return join(this.terminalOutputsDir, await this.hasher.hash(task));
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getFromLocalDir(task: Task) {
|
private async getFromLocalDir(task: Task) {
|
||||||
|
|||||||
@ -0,0 +1,61 @@
|
|||||||
|
import * as fs from 'fs';
|
||||||
|
import * as fsExtra from 'fs-extra';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
const WEEK_IN_MS = 1000 * 60 * 60 * 24 * 7;
|
||||||
|
|
||||||
|
const folder = process.argv[2];
|
||||||
|
|
||||||
|
removeOld(terminalOutputs());
|
||||||
|
removeOld(cachedFiles());
|
||||||
|
|
||||||
|
function terminalOutputs() {
|
||||||
|
try {
|
||||||
|
return fs.readdirSync(path.join(folder, 'terminalOutputs'));
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cachedFiles() {
|
||||||
|
try {
|
||||||
|
return fs.readdirSync(folder).filter(f => !f.endsWith('terminalOutputs'));
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeOld(records: string[]) {
|
||||||
|
try {
|
||||||
|
const time = mostRecentMTime(records);
|
||||||
|
|
||||||
|
records.forEach(r => {
|
||||||
|
const child = path.join(folder, r);
|
||||||
|
try {
|
||||||
|
const s = fs.statSync(child);
|
||||||
|
if (time - s.mtimeMs > WEEK_IN_MS) {
|
||||||
|
if (s.isDirectory()) {
|
||||||
|
try {
|
||||||
|
fsExtra.removeSync(`${child}.commit`);
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
fsExtra.removeSync(child);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
});
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mostRecentMTime(records: string[]) {
|
||||||
|
let mostRecentTime = 0;
|
||||||
|
records.forEach(r => {
|
||||||
|
const child = path.join(folder, r);
|
||||||
|
try {
|
||||||
|
const s = fs.statSync(child);
|
||||||
|
if (s.mtimeMs > mostRecentTime) {
|
||||||
|
mostRecentTime = s.mtimeMs;
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
});
|
||||||
|
return mostRecentTime;
|
||||||
|
}
|
||||||
@ -28,6 +28,7 @@ export class TaskOrchestrator {
|
|||||||
|
|
||||||
const r1 = await this.applyCachedResults(cached);
|
const r1 = await this.applyCachedResults(cached);
|
||||||
const r2 = await this.runRest(rest);
|
const r2 = await this.runRest(rest);
|
||||||
|
this.cache.removeOldCacheRecords();
|
||||||
return [...r1, ...r2];
|
return [...r1, ...r2];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,12 +110,16 @@ export class TaskOrchestrator {
|
|||||||
return this.cache.temporaryOutputPath(task).then(outputPath => {
|
return this.cache.temporaryOutputPath(task).then(outputPath => {
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
try {
|
try {
|
||||||
|
const env = { ...process.env };
|
||||||
|
if (outputPath) {
|
||||||
|
env.NX_TERMINAL_OUTPUT_PATH = outputPath;
|
||||||
|
}
|
||||||
const p = fork(this.getCommand(), this.getCommandArgs(task), {
|
const p = fork(this.getCommand(), this.getCommandArgs(task), {
|
||||||
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
||||||
env: { ...process.env, NX_TERMINAL_OUTPUT_PATH: outputPath }
|
env
|
||||||
});
|
});
|
||||||
p.on('close', code => {
|
p.on('close', code => {
|
||||||
if (code === 0) {
|
if (outputPath && code === 0) {
|
||||||
this.cache.put(task, outputPath, taskOutputs).then(() => {
|
this.cache.put(task, outputPath, taskOutputs).then(() => {
|
||||||
res(code);
|
res(code);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user