feat(relay): enrich request lifecycle telemetry for retries and outcomes

This commit is contained in:
2026-03-24 12:54:07 +00:00
parent 0faf79945f
commit 1ba0cbe8a9
3 changed files with 205 additions and 5 deletions
+51 -3
View File
@@ -109,6 +109,19 @@ const structuredRelayLog = (event, payload) => {
console.info(event, redactSensitive(payload));
};
const buildRelayRequestId = () => {
return `relay_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
};
const getElapsedMs = (startedAtMs) => {
return Math.max(0, Date.now() - startedAtMs);
};
const getStatusClass = (status) => {
if (typeof status !== "number") return "none";
return `${Math.floor(status / 100)}xx`;
};
const shouldRetryRelayError = ({ error, attempt, maxRetries }) => {
if (attempt >= maxRetries) return false;
@@ -226,11 +239,35 @@ export const forwardGetData = async ({
: resolvedTimeoutMs
};
const relayRequestId = buildRelayRequestId();
const startedAtMs = Date.now();
structuredRelayLog("relay_request_started", {
relayRequestId,
queryUrl,
baseUrl: resolvedBaseUrl,
timeoutMs: resolvedTimeoutMs,
maxRetries: resolvedMaxRetries,
retryBaseDelayMs: resolvedRetryBaseDelayMs,
retryMaxDelayMs: resolvedRetryMaxDelayMs
});
let lastError;
for (let attempt = 0; attempt <= resolvedMaxRetries; attempt += 1) {
try {
const { data } = await axios.get(finalUrl, axiosOptions);
const { data, status } = await axios.get(finalUrl, axiosOptions);
structuredRelayLog("relay_request_succeeded", {
relayRequestId,
queryUrl,
baseUrl: resolvedBaseUrl,
status,
statusClass: getStatusClass(status),
attemptsMade: attempt + 1,
retryCountUsed: attempt,
elapsedMs: getElapsedMs(startedAtMs)
});
return {
data,
@@ -248,13 +285,18 @@ export const forwardGetData = async ({
if (!retryEligible) {
error.__relayAlreadyLogged = true;
structuredRelayLog("relay_request_failed", {
relayRequestId,
queryUrl,
baseUrl: resolvedBaseUrl,
attempt: attempt + 1,
maxAttempts: resolvedMaxRetries + 1,
attemptsMade: attempt + 1,
retryCountUsed: attempt,
status: error?.response?.status,
statusClass: getStatusClass(error?.response?.status),
code: error?.code,
message: error?.message
message: error?.message,
elapsedMs: getElapsedMs(startedAtMs)
});
throw error;
}
@@ -266,14 +308,20 @@ export const forwardGetData = async ({
});
structuredRelayLog("relay_request_retrying", {
relayRequestId,
queryUrl,
baseUrl: resolvedBaseUrl,
attempt: attempt + 1,
maxAttempts: resolvedMaxRetries + 1,
attemptsMade: attempt + 1,
retryCountUsed: attempt,
remainingRetries: resolvedMaxRetries - attempt,
delayMs,
status: error?.response?.status,
statusClass: getStatusClass(error?.response?.status),
code: error?.code,
message: error?.message
message: error?.message,
elapsedMs: getElapsedMs(startedAtMs)
});
await wait(delayMs);