Skip to content

Commit 189dea6

Browse files
piehvladar
andauthored
fix(gatsby-core-utils): fix fetchRemoteFile when called in main process after being called in worker (#33932)
Co-authored-by: Vladimir Razuvaev <[email protected]>
1 parent 8ff9cc3 commit 189dea6

File tree

2 files changed

+141
-39
lines changed

2 files changed

+141
-39
lines changed

packages/gatsby-core-utils/src/__tests__/fetch-remote-file.js

+119-2
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,8 @@ async function createMockCache() {
209209
fs.ensureDir(tmpDir)
210210

211211
return {
212-
get: jest.fn(),
213-
set: jest.fn(),
212+
get: jest.fn(() => Promise.resolve(null)),
213+
set: jest.fn(() => Promise.resolve(null)),
214214
directory: tmpDir,
215215
}
216216
}
@@ -445,6 +445,123 @@ describe(`fetch-remote-file`, () => {
445445
expect(fsMove).toBeCalledTimes(0)
446446
})
447447

448+
it(`downloading a file in main process after downloading it in worker`, async () => {
449+
// we don't want to wait for polling to finish
450+
jest.useFakeTimers()
451+
jest.runAllTimers()
452+
453+
const cacheInternals = new Map()
454+
const workerCache = {
455+
get(key) {
456+
return Promise.resolve(cacheInternals.get(key))
457+
},
458+
set(key, value) {
459+
return Promise.resolve(cacheInternals.set(key, value))
460+
},
461+
directory: cache.directory,
462+
}
463+
464+
const fetchRemoteFileInstanceOne = getFetchInWorkerContext(`1`)
465+
466+
const resultFromWorker = await fetchRemoteFileInstanceOne({
467+
url: `http://external.com/logo.svg`,
468+
cache: workerCache,
469+
})
470+
471+
jest.runAllTimers()
472+
473+
const resultFromMain = await fetchRemoteFile({
474+
url: `http://external.com/logo.svg`,
475+
cache: workerCache,
476+
})
477+
478+
expect(resultFromWorker).not.toBeUndefined()
479+
expect(resultFromMain).not.toBeUndefined()
480+
481+
jest.useRealTimers()
482+
483+
expect(gotStream).toBeCalledTimes(1)
484+
expect(fsMove).toBeCalledTimes(1)
485+
})
486+
487+
it(`downloading a file in worker process after downloading it in main`, async () => {
488+
// we don't want to wait for polling to finish
489+
jest.useFakeTimers()
490+
jest.runAllTimers()
491+
492+
const cacheInternals = new Map()
493+
const workerCache = {
494+
get(key) {
495+
return Promise.resolve(cacheInternals.get(key))
496+
},
497+
set(key, value) {
498+
return Promise.resolve(cacheInternals.set(key, value))
499+
},
500+
directory: cache.directory,
501+
}
502+
503+
const fetchRemoteFileInstanceOne = getFetchInWorkerContext(`1`)
504+
505+
const resultFromMain = await fetchRemoteFile({
506+
url: `http://external.com/logo.svg`,
507+
cache: workerCache,
508+
})
509+
510+
jest.runAllTimers()
511+
512+
const resultFromWorker = await fetchRemoteFileInstanceOne({
513+
url: `http://external.com/logo.svg`,
514+
cache: workerCache,
515+
})
516+
517+
jest.runAllTimers()
518+
jest.useRealTimers()
519+
520+
expect(resultFromWorker).not.toBeUndefined()
521+
expect(resultFromMain).not.toBeUndefined()
522+
expect(gotStream).toBeCalledTimes(1)
523+
expect(fsMove).toBeCalledTimes(1)
524+
})
525+
526+
it(`downloading a file in worker process after downloading it in another worker`, async () => {
527+
// we don't want to wait for polling to finish
528+
jest.useFakeTimers()
529+
jest.runAllTimers()
530+
531+
const cacheInternals = new Map()
532+
const workerCache = {
533+
get(key) {
534+
return Promise.resolve(cacheInternals.get(key))
535+
},
536+
set(key, value) {
537+
return Promise.resolve(cacheInternals.set(key, value))
538+
},
539+
directory: cache.directory,
540+
}
541+
542+
const fetchRemoteFileInstanceOne = getFetchInWorkerContext(`1`)
543+
const fetchRemoteFileInstanceTwo = getFetchInWorkerContext(`2`)
544+
545+
const resultFromWorker1 = await fetchRemoteFileInstanceOne({
546+
url: `http://external.com/logo.svg`,
547+
cache: workerCache,
548+
})
549+
jest.runAllTimers()
550+
551+
const resultFromWorker2 = await fetchRemoteFileInstanceTwo({
552+
url: `http://external.com/logo.svg`,
553+
cache: workerCache,
554+
})
555+
556+
jest.runAllTimers()
557+
jest.useRealTimers()
558+
559+
expect(resultFromWorker1).not.toBeUndefined()
560+
expect(resultFromWorker2).not.toBeUndefined()
561+
expect(gotStream).toBeCalledTimes(1)
562+
expect(fsMove).toBeCalledTimes(1)
563+
})
564+
448565
it(`fails when 404 is triggered`, async () => {
449566
await expect(
450567
fetchRemoteFile({

packages/gatsby-core-utils/src/fetch-remote-file.ts

+22-37
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,6 @@ function pollUntilComplete(
105105
buildId: string,
106106
cb: (err?: Error, result?: string) => void
107107
): void {
108-
if (!IS_WORKER) {
109-
// We are not in a worker, so we shouldn't use the cache
110-
return void cb()
111-
}
112-
113108
cache.get(cacheIdForWorkers(url)).then(entry => {
114109
if (!entry || entry.buildId !== buildId) {
115110
return void cb()
@@ -160,14 +155,12 @@ async function fetchFile({
160155
return result
161156
}
162157

163-
if (IS_WORKER) {
164-
await cache.set(cacheIdForWorkers(url), {
165-
status: `pending`,
166-
result: null,
167-
workerId: WORKER_ID,
168-
buildId: BUILD_ID,
169-
})
170-
}
158+
await cache.set(cacheIdForWorkers(url), {
159+
status: `pending`,
160+
result: null,
161+
workerId: WORKER_ID,
162+
buildId: BUILD_ID,
163+
})
171164

172165
// See if there's response headers for this url
173166
// from a previous request.
@@ -231,7 +224,7 @@ async function fetchFile({
231224
}
232225
}
233226

234-
// Multiple workers have started the fetch and we need another check to only let one complete
227+
// Multiple processes have started the fetch and we need another check to only let one complete
235228
const cacheEntry = await cache.get(cacheIdForWorkers(url))
236229
if (cacheEntry && cacheEntry.workerId !== WORKER_ID) {
237230
return new Promise<string>((resolve, reject) => {
@@ -258,35 +251,27 @@ async function fetchFile({
258251
await fs.remove(tmpFilename)
259252
}
260253

261-
if (IS_WORKER) {
254+
await cache.set(cacheIdForWorkers(url), {
255+
status: `complete`,
256+
result: filename,
257+
workerId: WORKER_ID,
258+
buildId: BUILD_ID,
259+
})
260+
261+
return filename
262+
} catch (err) {
263+
// enable multiple processes to continue when done
264+
const cacheEntry = await cache.get(cacheIdForWorkers(url))
265+
266+
if (!cacheEntry || cacheEntry.workerId === WORKER_ID) {
262267
await cache.set(cacheIdForWorkers(url), {
263-
status: `complete`,
264-
result: filename,
268+
status: `failed`,
269+
result: err.toString ? err.toString() : err.message ? err.message : err,
265270
workerId: WORKER_ID,
266271
buildId: BUILD_ID,
267272
})
268273
}
269274

270-
return filename
271-
} catch (err) {
272-
// enable multiple workers to continue when done
273-
if (IS_WORKER) {
274-
const cacheEntry = await cache.get(cacheIdForWorkers(url))
275-
276-
if (!cacheEntry || cacheEntry.workerId === WORKER_ID) {
277-
await cache.set(cacheIdForWorkers(url), {
278-
status: `failed`,
279-
result: err.toString
280-
? err.toString()
281-
: err.message
282-
? err.message
283-
: err,
284-
workerId: WORKER_ID,
285-
buildId: BUILD_ID,
286-
})
287-
}
288-
}
289-
290275
throw err
291276
}
292277
}

0 commit comments

Comments
 (0)