diff --git a/lib/errors/index.test.ts b/lib/errors/index.test.ts index 2538b7a887..c2dd36edeb 100644 --- a/lib/errors/index.test.ts +++ b/lib/errors/index.test.ts @@ -27,8 +27,12 @@ describe('httperror', () => { }); describe('RequestInProgressError', () => { - it(`RequestInProgressError`, async () => { + it(`RequestInProgressError with retry`, async () => { const responses = await Promise.all([request.get('/test/slow'), request.get('/test/slow')]); + expect(new Set(responses.map((r) => r.status))).toEqual(new Set([200, 200])); + }); + it(`RequestInProgressError`, async () => { + const responses = await Promise.all([request.get('/test/slow4'), request.get('/test/slow4')]); expect(new Set(responses.map((r) => r.status))).toEqual(new Set([200, 503])); expect(new Set(responses.map((r) => r.headers['cache-control']))).toEqual(new Set([`public, max-age=${config.cache.routeExpire}`, `public, max-age=${config.requestTimeout / 1000}`])); expect(responses.filter((r) => r.text.includes('RequestInProgressError: This path is currently fetching, please come back later!'))).toHaveLength(1); @@ -63,19 +67,19 @@ describe('route throws an error', () => { const value = $(item).find('.debug-value').html()?.trim(); switch (key) { case 'Request Amount:': - expect(value).toBe('9'); + expect(value).toBe('11'); break; case 'Hot Routes:': - expect(value).toBe('6 /test/:id/:params?
'); + expect(value).toBe('8 /test/:id/:params?
'); break; case 'Hot Paths:': - expect(value).toBe('2 /test/error
2 /test/slow
1 /test/httperror
1 /test/config-not-found-error
1 /test/invalid-parameter-error
1 /thisDoesNotExist
1 /
'); + expect(value).toBe('2 /test/error
2 /test/slow
2 /test/slow4
1 /test/httperror
1 /test/config-not-found-error
1 /test/invalid-parameter-error
1 /thisDoesNotExist
1 /
'); break; case 'Hot Error Routes:': expect(value).toBe('5 /test/:id/:params?
'); break; case 'Hot Error Paths:': - expect(value).toBe('2 /test/error
1 /test/httperror
1 /test/slow
1 /test/config-not-found-error
1 /test/invalid-parameter-error
1 /thisDoesNotExist
'); + expect(value).toBe('2 /test/error
1 /test/httperror
1 /test/slow4
1 /test/config-not-found-error
1 /test/invalid-parameter-error
1 /thisDoesNotExist
'); break; default: } diff --git a/lib/middleware/cache.ts b/lib/middleware/cache.ts index 23924294fe..6c5596f5af 100644 --- a/lib/middleware/cache.ts +++ b/lib/middleware/cache.ts @@ -23,7 +23,21 @@ const middleware: MiddlewareHandler = async (ctx, next) => { const isRequesting = await cacheModule.globalCache.get(controlKey); if (isRequesting === '1') { - throw new RequestInProgressError('This path is currently fetching, please come back later!'); + let retryTimes = process.env.NODE_ENV === 'test' ? 1 : 10; + let bypass = false; + while (retryTimes > 0) { + // eslint-disable-next-line no-await-in-loop + await new Promise((resolve) => setTimeout(resolve, process.env.NODE_ENV === 'test' ? 3000 : 6000)); + // eslint-disable-next-line no-await-in-loop + if ((await cacheModule.globalCache.get(controlKey)) !== '1') { + bypass = true; + break; + } + retryTimes--; + } + if (!bypass) { + throw new RequestInProgressError('This path is currently fetching, please come back later!'); + } } const value = await cacheModule.globalCache.get(key); diff --git a/lib/routes/test/index.ts b/lib/routes/test/index.ts index d7481e9425..8cba7553c4 100644 --- a/lib/routes/test/index.ts +++ b/lib/routes/test/index.ts @@ -376,6 +376,10 @@ async function handler(ctx) { await wait(1000); } + if (ctx.req.param('id') === 'slow4') { + await wait(4000); + } + if (ctx.req.query('mode') === 'fulltext') { item = [ {