@magile/nx-distributed-cache
Version:
Distributed Cache For Your NX build. Optimize your build time by caching the artifacts across multiple devices.
115 lines (88 loc) • 3.99 kB
text/typescript
import {ProjectGraph} from '@nrwl/workspace/src/core/project-graph';
import {NxJson} from '@nrwl/workspace/src/core/shared-interfaces';
import {
defaultTasksRunner,
DefaultTasksRunnerOptions,
RemoteCache
} from '@nrwl/workspace/src/tasks-runner/default-tasks-runner';
import {AffectedEvent, Task, TasksRunner} from '@nrwl/workspace/src/tasks-runner/tasks-runner';
import {Observable} from 'rxjs';
import * as fs from 'fs';
import * as fsExtra from 'fs-extra';
import * as path from 'path';
import {S3Adapter, S3AdapterOptions} from "./s3-adapter";
import * as chalk from 'chalk';
class NXDistributedS3Cache implements RemoteCache {
private readonly S3Adapter: S3Adapter;
constructor(private remoteDirectory: string, options) {
this.S3Adapter = new S3Adapter(options);
}
retrieve = async (hash: string, cacheDirectory: string): Promise<boolean> => {
console.debug('NXDistributedCache::retrieve');
if (!this.S3Adapter.isReady) {
console.log(chalk.yellow('Configuration missing/invalid. Skipping...'));
return Promise.resolve(false);
}
const hashCommit = hash + '.commit';
const local = path.join(cacheDirectory, hash);
const remote = path.join(this.remoteDirectory, hash);
const localCommit = path.join(cacheDirectory, hashCommit);
const remoteCommit = path.join(this.remoteDirectory, hashCommit);
if (!fs.existsSync(remote)) {
console.log('No entry in local nx-cache not found. Checking remote...');
let commitFile;
try {
commitFile = await this.S3Adapter.getFile(hashCommit);
} catch (e) {
console.log(chalk.yellow('Distributed cache: No entry found. Cache MISS!'));
return Promise.resolve(false);
}
console.log(chalk.green('Entry in remote cache found. Downloading content...'));
fs.mkdirSync(remote, {recursive: true})
fs.writeFileSync(remoteCommit, commitFile.toString())
await this.S3Adapter.downloadDirectory(hash, this.remoteDirectory);
console.log('Download finished. Processing cached content...');
}
if (fs.existsSync(remote)) {
console.debug(chalk.green.bold('NXDistributedCache::retrieve - cache HIT'));
fsExtra.copySync(remote, local);
fsExtra.copySync(remoteCommit, localCommit);
return Promise.resolve(true);
}
return Promise.resolve(false);
}
store = async (hash: string, cacheDirectory: string): Promise<boolean> => {
console.debug(chalk.blue('NXDistributedCache::store'));
const hashCommit = hash + '.commit';
const local = path.join(cacheDirectory, hash);
const remote = path.join(this.remoteDirectory, hash);
const localCommit = path.join(cacheDirectory, hashCommit);
const remoteCommit = path.join(this.remoteDirectory, hashCommit);
const start = Date.now();
if (this.S3Adapter.isReady) {
this.S3Adapter.uploadFile(localCommit, hashCommit);
await this.S3Adapter.uploadDir(local, hash);
console.log(`Uploaded to distributed cache. This took ${Date.now() - start}ms`);
console.log(chalk.green(`${hash} successfully stored in distributed cache.`));
}
fsExtra.copySync(local, remote);
fsExtra.copySync(localCommit, remoteCommit);
return Promise.resolve(true);
}
}
export type CustomTasksRunnerOptions = DefaultTasksRunnerOptions & {
remoteDirectory: string;
distributedCacheOptions: S3AdapterOptions
}
export const customTasksRunner: TasksRunner<CustomTasksRunnerOptions> =
(tasks: Task[], options: CustomTasksRunnerOptions, context?: {
target?: string;
initiatingProject?: string | null;
projectGraph: ProjectGraph;
nxJson: NxJson;
}): Observable<AffectedEvent> => {
console.log(chalk.blue.bold('Executing customTaskRunner: NXDistributedCache'));
options.remoteCache = new NXDistributedS3Cache(options.remoteDirectory, options.distributedCacheOptions);
return defaultTasksRunner(tasks, options, context);
}
export default customTasksRunner;