Skip to content

Commit bb05f75

Browse files
VIA-615 AJ Move retries to different place
- add retry for fetchContentForVaccine() - make log level as warn in fetchContentForVaccine() as it is retried from outside - reduce timeout as API is retried
1 parent 0e2beb9 commit bb05f75

File tree

3 files changed

+36
-23
lines changed

3 files changed

+36
-23
lines changed

src/_lambda/content-cache-hydrator/content-fetcher.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ describe("fetchContentForVaccine", () => {
2323
const actual = await fetchContentForVaccine(VaccineType.RSV);
2424
expect(axios.get).toHaveBeenCalledWith(
2525
`${testApiEndpoint}${CONTENT_API_PATH_PREFIX}${VaccineInfo[VaccineType.RSV].contentPath}`,
26-
{ headers: { accept: "application/json", apikey: testApiKey }, timeout: 30000 },
26+
{ headers: { accept: "application/json", apikey: testApiKey }, timeout: 10000 },
2727
);
2828
expect(actual).toBe(JSON.stringify(testApiContent));
2929
});

src/_lambda/content-cache-hydrator/content-fetcher.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,26 @@ const fetchContentForVaccine = async (vaccineType: VaccineType): Promise<string>
2020
accept: "application/json",
2121
apikey: apiKey,
2222
},
23-
timeout: 30000,
23+
timeout: 10000,
2424
});
2525
log.info({ context: { uri, vaccineType } }, "Successfully fetched content from API");
2626
return JSON.stringify(response.data);
2727
} catch (error) {
2828
if (error instanceof AxiosError) {
29-
log.error({
30-
error: {
31-
code: error.code,
32-
status: error.status,
33-
message: error.message,
34-
response_data: error.response?.data,
29+
log.warn(
30+
{
31+
error: {
32+
code: error.code,
33+
status: error.status,
34+
message: error.message,
35+
response_data: error.response?.data,
36+
},
37+
context: { uri, vaccineType },
3538
},
36-
context: { uri, vaccineType },
37-
});
39+
"AxiosError in getting vaccine content from nhs.uk API",
40+
);
3841
} else {
39-
log.error({ context: { uri, vaccineType } }, "Error in getting vaccine content from nhs.uk API");
42+
log.warn({ context: { uri, vaccineType } }, "Error in getting vaccine content from nhs.uk API");
4043
}
4144
throw error;
4245
}

src/_lambda/content-cache-hydrator/handler.ts

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,24 @@ async function hydrateCacheForVaccine(
4949
approvalEnabled: boolean,
5050
forceUpdate: boolean,
5151
): Promise<HydrateCacheStatus> {
52+
log.info({ context: { vaccineType } }, "Hydrating cache for given vaccine");
5253
const status: HydrateCacheStatus = { invalidatedCount: 0, failureCount: 0 };
5354

55+
const rateLimitDelayMillis: number = 1000 / ((await config.CONTENT_API_RATE_LIMIT_PER_MINUTE) / 60);
56+
const rateLimitDelayWithMargin: number = 2 * rateLimitDelayMillis; // to keep ourselves well within the budget
57+
5458
try {
55-
const content: string = await fetchContentForVaccine(vaccineType);
59+
const content: string = await retry(() => fetchContentForVaccine(vaccineType), {
60+
retries: 2,
61+
delay: (attempt: number) => {
62+
const delayMillis = rateLimitDelayWithMargin * Math.pow(2, attempt + 1);
63+
log.warn(
64+
{ context: { vaccineType, attempt, delayMillis } },
65+
"Failed to fetch content for given vaccine, trying again",
66+
);
67+
return delayMillis;
68+
},
69+
});
5670
const filteredContent: VaccinePageContent = getFilteredContentForVaccine(vaccineType, content);
5771

5872
if (!approvalEnabled) {
@@ -151,22 +165,18 @@ const runContentCacheHydrator = async (event: ContentCacheHydratorEvent) => {
151165
const rateLimitDelayMillis: number = 1000 / ((await config.CONTENT_API_RATE_LIMIT_PER_MINUTE) / 60);
152166
const rateLimitDelayWithMargin: number = 2 * rateLimitDelayMillis; // to keep ourselves well within the budget
153167
log.info(`Delay used between calls to rate limit content API is ${rateLimitDelayWithMargin}ms`);
168+
154169
for (const vaccine of vaccinesToRunOn) {
155-
const status = await retry(
156-
async () => hydrateCacheForVaccine(vaccine, await config.CONTENT_CACHE_IS_CHANGE_APPROVAL_ENABLED, forceUpdate),
157-
{
158-
retries: 3,
159-
delay: (attempt) => {
160-
const delayMillis = rateLimitDelayWithMargin * Math.pow(2, attempt);
161-
log.warn({ context: { vaccine, attempt, delayMillis } }, "Failed to hydrate cache, trying again");
162-
return delayMillis;
163-
},
164-
},
170+
const status = await hydrateCacheForVaccine(
171+
vaccine,
172+
await config.CONTENT_CACHE_IS_CHANGE_APPROVAL_ENABLED,
173+
forceUpdate,
165174
);
166175

167176
invalidatedCount += status.invalidatedCount;
168177
failureCount += status.failureCount;
169-
await new Promise((f) => setTimeout(f, rateLimitDelayWithMargin)); // sleep
178+
179+
await new Promise((f) => setTimeout(f, rateLimitDelayWithMargin)); // sleep to rate limit
170180
}
171181

172182
log.info({ context: { failureCount, invalidatedCount } }, "Finished hydrating content cache: report");

0 commit comments

Comments
 (0)