Skip to content

Commit

Permalink
Update to re-use cache while revalidate is erroring (#34931)
Browse files Browse the repository at this point in the history
  • Loading branch information
ijjk committed Mar 2, 2022
1 parent 937ab16 commit e51d262
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 10 deletions.
30 changes: 21 additions & 9 deletions packages/next/server/response-cache.ts
Expand Up @@ -60,15 +60,17 @@ type ResponseGenerator = (
hadCache: boolean
) => Promise<ResponseCacheEntry | null>

type IncrementalCacheItem = {
revalidateAfter?: number | false
curRevalidate?: number | false
revalidate?: number | false
value: IncrementalCacheValue | null
isStale?: boolean
isMiss?: boolean
} | null

interface IncrementalCache {
get: (key: string) => Promise<{
revalidateAfter?: number | false
curRevalidate?: number | false
revalidate?: number | false
value: IncrementalCacheValue | null
isStale?: boolean
isMiss?: boolean
} | null>
get: (key: string) => Promise<IncrementalCacheItem>
set: (
key: string,
data: IncrementalCacheValue | null,
Expand Down Expand Up @@ -123,8 +125,9 @@ export default class ResponseCache {
// `pendingResponses` to ensure that any any other calls will reuse the
// same promise until we've fully finished our work.
;(async () => {
let cachedResponse: IncrementalCacheItem = null
try {
const cachedResponse = key ? await this.incrementalCache.get(key) : null
cachedResponse = key ? await this.incrementalCache.get(key) : null
if (cachedResponse && !context.isManualRevalidate) {
resolve({
isStale: cachedResponse.isStale,
Expand Down Expand Up @@ -169,6 +172,15 @@ export default class ResponseCache {
)
}
} catch (err) {
// when a getStaticProps path is erroring we automatically re-set the
// existing cache under a new expiration to prevent non-stop retrying
if (cachedResponse && key) {
await this.incrementalCache.set(
key,
cachedResponse.value,
Math.min(Math.max(cachedResponse.revalidate || 3, 3), 30)
)
}
// while revalidating in the background we can't reject as
// we already resolved the cache entry so log the error here
if (resolved) {
Expand Down
44 changes: 44 additions & 0 deletions test/e2e/prerender.test.ts
Expand Up @@ -1905,6 +1905,50 @@ describe('Prerender', () => {
}

if (!(global as any).isNextDev) {
it('should automatically reset cache TTL when an error occurs and build cache was available', async () => {
await next.patchFile('error.txt', 'yes')
await waitFor(2000)

for (let i = 0; i < 5; i++) {
const res = await fetchViaHTTP(
next.url,
'/blocking-fallback/test-errors-1'
)
expect(res.status).toBe(200)
}
await next.deleteFile('error.txt')
expect(
next.cliOutput.match(
/throwing error for \/blocking-fallback\/test-errors-1/
).length
).toBe(1)
})

it('should automatically reset cache TTL when an error occurs and runtime cache was available', async () => {
const res = await fetchViaHTTP(
next.url,
'/blocking-fallback/test-errors-2'
)

expect(res.status).toBe(200)
await waitFor(2000)
await next.patchFile('error.txt', 'yes')

for (let i = 0; i < 5; i++) {
const res = await fetchViaHTTP(
next.url,
'/blocking-fallback/test-errors-2'
)
expect(res.status).toBe(200)
}
await next.deleteFile('error.txt')
expect(
next.cliOutput.match(
/throwing error for \/blocking-fallback\/test-errors-2/
).length
).toBe(1)
})

it('should handle manual revalidate for fallback: blocking', async () => {
const res = await fetchViaHTTP(
next.url,
Expand Down
18 changes: 17 additions & 1 deletion test/e2e/prerender/pages/blocking-fallback/[slug].js
@@ -1,15 +1,31 @@
import fs from 'fs'
import path from 'path'
import React from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'

export async function getStaticPaths() {
return {
paths: [],
paths: [
{
params: { slug: 'test-errors-1' },
},
],
fallback: 'blocking',
}
}

export async function getStaticProps({ params }) {
if (params.slug.startsWith('test-errors')) {
const errorFile = path.join(process.cwd(), 'error.txt')
if (fs.existsSync(errorFile)) {
const data = await fs.readFileSync(errorFile, 'utf8')
if (data.trim() === 'yes') {
throw new Error('throwing error for /blocking-fallback/' + params.slug)
}
}
}

await new Promise((resolve) => setTimeout(resolve, 1000))

return {
Expand Down

0 comments on commit e51d262

Please sign in to comment.