Skip to content
This repository was archived by the owner on Nov 18, 2024. It is now read-only.

Commit 6853954

Browse files
committed
improve retries
1 parent dbc8bad commit 6853954

File tree

3 files changed

+77
-16
lines changed

3 files changed

+77
-16
lines changed

metrics-collector/README.md

+10
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,13 @@ See the collected metrics at:
1717

1818
- `pr_metrics.json` or `pr_metrics.csv`
1919
- TODO: `usage_metrics.json`...
20+
21+
## metrics service
22+
23+
```sh
24+
docker compose build
25+
docker compose up
26+
27+
# test multiple concurrent requests
28+
hey -n 1000 -c 50 -m POST -H "Content-Type: application/json" -d '{"metricName":"test_concurrent_metric","value":1,"labels":{"test":"concurrency"},"operation":"increment"}' http://localhost:3001/api/v1/metrics
29+
```

metrics-collector/src/npm-metrics.ts

+13-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as fs from "fs";
22
import * as path from "path";
33
import { createObjectCsvWriter } from "csv-writer";
4-
import { readJsonFile, writeJsonFile } from "./utils";
4+
import { fetchWithRetry, readJsonFile, writeJsonFile } from "./utils";
55
import { postMetric } from "./post-metric";
66

77
// Define the npm packages to collect metrics for
@@ -52,7 +52,7 @@ export const collectNpmMetrics = async (metricDate: string) => {
5252
}
5353

5454
console.info("NPM metrics collected successfully");
55-
}
55+
};
5656

5757
// Save collected total downloads and last 30d downloads to a local file
5858
export async function saveNpmMetrics() {
@@ -125,25 +125,22 @@ async function getNpmDownloadCount(
125125
onlyLastMonth?: boolean,
126126
dateRange?: { begin: string; end: string }
127127
): Promise<{ downloads: number; start: string }> {
128-
try {
129-
let url = `https://api.npmjs.org/downloads/point`;
130-
if (onlyLastMonth) {
131-
url += `/last-month/${packageName}`;
132-
} else if (dateRange) {
133-
url += `/${dateRange.begin}:${dateRange.end}/${packageName}`;
134-
} else {
135-
url += `/1970-01-01:2100-01-01/${packageName}`;
136-
}
128+
let url = `https://api.npmjs.org/downloads/point`;
129+
if (onlyLastMonth) {
130+
url += `/last-month/${packageName}`;
131+
} else if (dateRange) {
132+
url += `/${dateRange.begin}:${dateRange.end}/${packageName}`;
133+
} else {
134+
url += `/1970-01-01:2100-01-01/${packageName}`;
135+
}
137136

138-
const response = await fetch(url);
139-
if (!response.ok) {
140-
throw new Error(`HTTP error! Status: ${response.status}`);
141-
}
137+
try {
138+
const response = await fetchWithRetry(url);
142139
const data = await response.json();
143140
return data;
144141
} catch (error) {
145142
console.error(
146-
`Error fetching download count for package ${packageName}:`,
143+
`Error fetching download count for package ${packageName} from ${url}:`,
147144
error
148145
);
149146
throw error;

metrics-collector/src/utils.ts

+54
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,57 @@ export const getYesterdayDate = () => {
2020
yesterday.setDate(yesterday.getDate() - 1);
2121
return yesterday.toISOString().split("T")[0];
2222
};
23+
24+
interface FetchWithRetryOptions {
25+
maxRetries?: number;
26+
retryDelay?: number;
27+
timeout?: number;
28+
}
29+
30+
export async function fetchWithRetry(
31+
url: string,
32+
options: RequestInit & FetchWithRetryOptions = {}
33+
): Promise<Response> {
34+
const {
35+
maxRetries = 3,
36+
retryDelay = 1000,
37+
timeout = 10000,
38+
...fetchOptions
39+
} = options;
40+
41+
let retries = 0;
42+
while (retries < maxRetries) {
43+
try {
44+
const controller = new AbortController();
45+
const id = setTimeout(() => controller.abort(), timeout);
46+
47+
const response = await fetch(url, {
48+
...fetchOptions,
49+
signal: controller.signal,
50+
});
51+
52+
if (!response.ok) {
53+
const errorData = await response.text();
54+
console.error(
55+
`HTTP error! Status: ${response.status}, Response: ${errorData}`
56+
);
57+
throw new Error(
58+
`HTTP error! Status: ${response.status}, Response: ${errorData}`
59+
);
60+
}
61+
62+
clearTimeout(id);
63+
64+
return response;
65+
} catch (error) {
66+
console.error(`Attempt ${retries + 1} failed:`, error);
67+
retries++;
68+
if (retries >= maxRetries) {
69+
throw error;
70+
}
71+
const exponentialDelay = retryDelay * Math.pow(2, retries - 1);
72+
await new Promise((resolve) => setTimeout(resolve, exponentialDelay));
73+
}
74+
}
75+
throw new Error("Max retries reached");
76+
}

0 commit comments

Comments
 (0)