diff --git a/packages/core/cache/src/FSCache.js b/packages/core/cache/src/FSCache.js index 90e9a136b0a..54da08a76d6 100644 --- a/packages/core/cache/src/FSCache.js +++ b/packages/core/cache/src/FSCache.js @@ -151,6 +151,21 @@ export class FSCache implements Cache { await Promise.all(writePromises); } + async deleteLargeBlob(key: string): Promise { + const deletePromises: Promise[] = []; + + let i = 0; + let filePath = this.#getFilePath(key, i); + + while (await this.fs.exists(filePath)) { + deletePromises.push(this.fs.rimraf(filePath)); + i += 1; + filePath = this.#getFilePath(key, i); + } + + await Promise.all(deletePromises); + } + async get(key: string): Promise { try { let data = await this.fs.readFile(this._getCachePath(key)); diff --git a/packages/core/cache/src/IDBCache.browser.js b/packages/core/cache/src/IDBCache.browser.js index 01e788d9f6b..3c8cd75d828 100644 --- a/packages/core/cache/src/IDBCache.browser.js +++ b/packages/core/cache/src/IDBCache.browser.js @@ -133,6 +133,10 @@ export class IDBCache implements Cache { return this.setBlob(key, contents); } + async deleteLargeBlob(key: string): Promise { + await (await this.store).delete(STORE_NAME, key); + } + refresh(): void { // NOOP } diff --git a/packages/core/cache/src/LMDBCache.js b/packages/core/cache/src/LMDBCache.js index b2eef533203..644be76c117 100644 --- a/packages/core/cache/src/LMDBCache.js +++ b/packages/core/cache/src/LMDBCache.js @@ -117,6 +117,10 @@ export class LMDBCache implements Cache { return this.fsCache.setLargeBlob(key, contents, options); } + deleteLargeBlob(key: string): Promise { + return this.fsCache.deleteLargeBlob(key); + } + refresh(): void { // Reset the read transaction for the store. This guarantees that // the next read will see the latest changes to the store. diff --git a/packages/core/core/src/RequestTracker.js b/packages/core/core/src/RequestTracker.js index f686152a7f8..56bd160275d 100644 --- a/packages/core/core/src/RequestTracker.js +++ b/packages/core/core/src/RequestTracker.js @@ -1352,6 +1352,9 @@ export default class RequestTracker { let serialisedGraph = this.graph.serialize(); + // Delete an existing request graph cache, to prevent invalid states + await this.options.cache.deleteLargeBlob(requestGraphKey); + let total = 0; const serialiseAndSet = async ( key: string, @@ -1440,33 +1443,23 @@ export default class RequestTracker { } } - queue - .add(() => - serialiseAndSet(requestGraphKey, { - ...serialisedGraph, - nodes: undefined, - }), - ) - .catch(() => { - // Handle promise rejection - }); + try { + await queue.run(); - let opts = getWatcherOptions(this.options); - let snapshotPath = path.join(this.options.cacheDir, snapshotKey + '.txt'); - queue - .add(() => - this.options.inputFS.writeSnapshot( - this.options.watchDir, - snapshotPath, - opts, - ), - ) - .catch(() => { - // Handle promise rejection + // Set the request graph after the queue is flushed to avoid writing an invalid state + await serialiseAndSet(requestGraphKey, { + ...serialisedGraph, + nodes: undefined, }); - try { - await queue.run(); + let opts = getWatcherOptions(this.options); + let snapshotPath = path.join(this.options.cacheDir, snapshotKey + '.txt'); + + await this.options.inputFS.writeSnapshot( + this.options.watchDir, + snapshotPath, + opts, + ); } catch (err) { // If we have aborted, ignore the error and continue if (!signal?.aborted) throw err; diff --git a/packages/core/types-internal/src/Cache.js b/packages/core/types-internal/src/Cache.js index cb4eb862fba..ff3217b43d4 100644 --- a/packages/core/types-internal/src/Cache.js +++ b/packages/core/types-internal/src/Cache.js @@ -18,6 +18,7 @@ export interface Cache { contents: Buffer | string, options?: {|signal?: AbortSignal|}, ): Promise; + deleteLargeBlob(key: string): Promise; getBuffer(key: string): Promise; /** * In a multi-threaded environment, where there are potentially multiple Cache