From 17f71e54600ab0b8d4fd42a8611654166c69efb9 Mon Sep 17 00:00:00 2001 From: Enzo Mercanti Date: Wed, 7 Feb 2024 09:59:42 -0300 Subject: [PATCH] fix: add retry to sendMetric to avoid connection errors --- CHANGELOG.md | 3 ++ node/utils/metrics/metrics.test.ts | 61 ++++++++++++++++++++++++++++++ node/utils/metrics/metrics.ts | 15 +++++++- 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 node/utils/metrics/metrics.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index f6370569..df62974f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Fixed +- Add retries to `sendMetric` to avoid connection errors + ## [0.48.0] - 2024-01-19 ### Added diff --git a/node/utils/metrics/metrics.test.ts b/node/utils/metrics/metrics.test.ts new file mode 100644 index 00000000..c6a34d83 --- /dev/null +++ b/node/utils/metrics/metrics.test.ts @@ -0,0 +1,61 @@ +import axios from 'axios' + +import { sendMetric } from './metrics' + +jest.mock('axios') +afterEach(() => { + jest.resetAllMocks() +}) + +describe('when calling sendMetrics', () => { + it('should call axios.post', async () => { + const metric = { + account: 'account', + description: 'description', + kind: 'kind', + name: 'b2b-suite-buyerorg-data' as const, + } + + await sendMetric(metric) + + expect(axios.post).toBeCalledTimes(1) + }) + + it('should retry on failure', async () => { + const metric = { + account: 'account', + description: 'description', + kind: 'kind', + name: 'b2b-suite-buyerorg-data' as const, + } + + jest + .spyOn(axios, 'post') + .mockImplementation() + .mockRejectedValueOnce(new Error('error')) + + await sendMetric(metric) + + expect(axios.post).toBeCalledTimes(2) + }) + + it('should fail after max retries', async () => { + const metric = { + account: 'account', + description: 'description', + kind: 'kind', + name: 'b2b-suite-buyerorg-data' as const, + } + + jest + .spyOn(axios, 'post') + .mockImplementation() + .mockRejectedValue(new Error('Error')) + + await expect(async () => { + await sendMetric(metric) + }).rejects.toThrowError('Error - after 2 retries.') + + expect(axios.post).toBeCalledTimes(3) + }) +}) diff --git a/node/utils/metrics/metrics.ts b/node/utils/metrics/metrics.ts index df2d8ecd..bd1e6289 100644 --- a/node/utils/metrics/metrics.ts +++ b/node/utils/metrics/metrics.ts @@ -1,6 +1,8 @@ import axios from 'axios' const ANALYTICS_URL = 'https://rc.vtex.com/api/analytics/schemaless-events' +const MAX_RETRIES = 2 +const RETRY_INTERVAL = 1000 // 1 second export const B2B_METRIC_NAME = 'b2b-suite-buyerorg-data' @@ -11,6 +13,15 @@ export interface Metric { readonly name: typeof B2B_METRIC_NAME } -export const sendMetric = async (metric: Metric) => { - await axios.post(ANALYTICS_URL, metric) +export const sendMetric = async (metric: Metric, retries = 0) => { + try { + await axios.post(ANALYTICS_URL, metric) + } catch (error) { + if (retries < MAX_RETRIES) { + await new Promise((resolve) => setTimeout(resolve, RETRY_INTERVAL)) + await sendMetric(metric, retries + 1) + } else { + throw new Error(`${error.message} - after ${MAX_RETRIES} retries.`) + } + } }