Skip to content

Commit 7d71276

Browse files
committed
fix: prevent logging the retry message many times
1 parent 5966b61 commit 7d71276

File tree

3 files changed

+84
-2
lines changed

3 files changed

+84
-2
lines changed

src/Client.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { findRefByLabel } from "./lib/findRefByLabel"
88
import { getPreviewCookie } from "./lib/getPreviewCookie"
99
import { minifyGraphQLQuery } from "./lib/minifyGraphQLQuery"
1010
import { someTagsFilter } from "./lib/someTagsFilter"
11+
import { throttledLog } from "./lib/throttledLog"
1112
import { typeFilter } from "./lib/typeFilter"
1213

1314
import type { Query } from "./types/api/query"
@@ -1737,8 +1738,9 @@ export class Client<
17371738

17381739
const badRef = new URL(url).searchParams.get("ref")
17391740
const issue = error instanceof RefNotFoundError ? "invalid" : "expired"
1740-
console.warn(
1741-
`The ref (${badRef}) was ${issue}. Now retrying with the latest master ref (${masterRef}). If you were previewing content, the response will not include draft content.`,
1741+
throttledLog(
1742+
`[@prismicio/client] The ref (${badRef}) was ${issue}. Now retrying with the latest master ref (${masterRef}). If you were previewing content, the response will not include draft content.`,
1743+
{ level: "warn" },
17421744
)
17431745

17441746
return await this._get({ ...params, ref: masterRef }, attemptCount + 1)

src/lib/throttledLog.ts

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const THROTTLE_THRESHOLD_MS = 5000
2+
3+
let lastMessage: string | undefined
4+
let lastCalledAt = 0
5+
6+
/**
7+
* Logs a message. If the message is identical the immediate previous logged
8+
* message and that message was logged within 5 seconds of the current call, the
9+
* log is ignored. This throttle behavior prevents identical messages from
10+
* flodding the console.
11+
*
12+
* @param message - A message to log.
13+
* @param config - Configuration for the log.
14+
*/
15+
export const throttledLog = (
16+
message: string,
17+
config: {
18+
/**
19+
* The log level. Matches the global `console` log levels.
20+
*/
21+
level?: "log" | "warn" | "error"
22+
} = {},
23+
): void => {
24+
const { level = "log" } = config
25+
26+
lastCalledAt = Date.now()
27+
28+
if (
29+
message === lastMessage &&
30+
Date.now() - lastCalledAt < THROTTLE_THRESHOLD_MS
31+
) {
32+
return
33+
}
34+
35+
lastMessage = message
36+
37+
// eslint-disable-next-line no-console
38+
console[level](message)
39+
}

test/__testutils__/testInvalidRefRetry.ts

+41
Original file line numberDiff line numberDiff line change
@@ -167,4 +167,45 @@ export const testInvalidRefRetry = (args: TestInvalidRefRetryArgs): void => {
167167

168168
expect(triedRefs.size).toBe(3)
169169
})
170+
171+
it("throttles log", async (ctx) => {
172+
const client = createTestClient({ ctx })
173+
const badRef = ctx.mock.api.ref().ref
174+
175+
mockPrismicRestAPIV2({ ctx })
176+
177+
const endpoint = new URL(
178+
"documents/search",
179+
`${client.documentAPIEndpoint}/`,
180+
).toString()
181+
let attempts = 0
182+
ctx.server.use(
183+
rest.get(endpoint, (_req, res, ctx) => {
184+
if (attempts < 2) {
185+
attempts++
186+
187+
// We purposely return the bad ref again
188+
// to force a loop.
189+
return res(
190+
ctx.json({
191+
type: "api_notfound_error",
192+
message: `Master ref is: ${badRef}`,
193+
}),
194+
ctx.status(404),
195+
)
196+
}
197+
}),
198+
)
199+
200+
const consoleWarnSpy = vi
201+
.spyOn(console, "warn")
202+
.mockImplementation(() => void 0)
203+
await args.run(client, { ref: badRef })
204+
205+
// The client should make two attemps but only log once.
206+
expect(attempts).toBe(2)
207+
expect(consoleWarnSpy).toHaveBeenCalledTimes(1)
208+
209+
consoleWarnSpy.mockRestore()
210+
})
170211
}

0 commit comments

Comments
 (0)