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
@@ -43,6 +43,7 @@ const test = (name, fn) => tests.push({ name, fn });
test("forwardGetData retries retryable HTTP status and then succeeds", async () => {
let callCount = 0;
const infoLogs = [];
const mod = loadRelayForwardingModule({
axios: {
@@ -61,7 +62,13 @@ test("forwardGetData retries retryable HTTP status and then succeeds", async ()
hashAPIPath: () => "&hash=abc",
azureHeaders: () => ({ headers: { Authorization: "Bearer token" } }),
redactSensitive: (value) => value,
consoleLogger: () => {}
consoleLogger: () => {},
console: {
log: () => {},
info: (...args) => infoLogs.push(args),
warn: () => {},
error: () => {}
}
});
const result = await mod.forwardGetData({
@@ -74,10 +81,39 @@ test("forwardGetData retries retryable HTTP status and then succeeds", async ()
assert.strictEqual(callCount, 2);
assert.deepStrictEqual(result.data, { ok: true });
assert.strictEqual(result.accessToken, "token");
const eventNames = infoLogs.map((entry) => entry[0]);
assert.ok(eventNames.includes("relay_request_started"));
assert.ok(eventNames.includes("relay_request_retrying"));
assert.ok(eventNames.includes("relay_request_succeeded"));
const retryEvent = infoLogs.find(
(entry) => entry[0] === "relay_request_retrying"
);
assert.ok(retryEvent);
const retryPayload = retryEvent[1];
assert.strictEqual(retryPayload.statusClass, "5xx");
assert.strictEqual(retryPayload.attemptsMade, 1);
assert.strictEqual(retryPayload.retryCountUsed, 0);
assert.strictEqual(retryPayload.remainingRetries, 1);
assert.ok(typeof retryPayload.relayRequestId === "string");
const successEvent = infoLogs.find(
(entry) => entry[0] === "relay_request_succeeded"
);
assert.ok(successEvent);
const successPayload = successEvent[1];
assert.strictEqual(successPayload.statusClass, "none");
assert.strictEqual(successPayload.attemptsMade, 2);
assert.strictEqual(successPayload.retryCountUsed, 1);
assert.ok(typeof successPayload.elapsedMs === "number");
});
test("forwardGetData does not retry non-retryable HTTP status", async () => {
let callCount = 0;
const infoLogs = [];
const mod = loadRelayForwardingModule({
axios: {
@@ -92,7 +128,13 @@ test("forwardGetData does not retry non-retryable HTTP status", async () => {
hashAPIPath: () => "&hash=abc",
azureHeaders: () => ({ headers: {} }),
redactSensitive: (value) => value,
consoleLogger: () => {}
consoleLogger: () => {},
console: {
log: () => {},
info: (...args) => infoLogs.push(args),
warn: () => {},
error: () => {}
}
});
let thrown = null;
@@ -109,6 +151,17 @@ test("forwardGetData does not retry non-retryable HTTP status", async () => {
assert.ok(thrown);
assert.strictEqual(callCount, 1);
const failedEvent = infoLogs.find(
(entry) => entry[0] === "relay_request_failed"
);
assert.ok(failedEvent);
const failedPayload = failedEvent[1];
assert.strictEqual(failedPayload.statusClass, "4xx");
assert.strictEqual(failedPayload.attemptsMade, 1);
assert.strictEqual(failedPayload.retryCountUsed, 0);
assert.ok(typeof failedPayload.elapsedMs === "number");
});
test("forwardGetData does not retry unauthorized status", async () => {
@@ -258,6 +311,64 @@ test("forwardGetData applies timeout and appendHash=false behavior", async () =>
assert.strictEqual(capturedOptions.headers.Accept, "application/json");
});
test("forwardGetData telemetry request id is stable across lifecycle events", async () => {
const infoLogs = [];
let callCount = 0;
const mod = loadRelayForwardingModule({
axios: {
get: async () => {
callCount += 1;
if (callCount === 1) {
const error = new Error("service unavailable");
error.response = { status: 503 };
throw error;
}
return { data: { ok: true }, status: 200 };
}
},
getToken: async () => ({ access_token: "token" }),
hashAPIPath: () => "&hash=abc",
azureHeaders: () => ({ headers: {} }),
redactSensitive: (value) => value,
consoleLogger: () => {},
console: {
log: () => {},
info: (...args) => infoLogs.push(args),
warn: () => {},
error: () => {}
}
});
await mod.forwardGetData({
queryUrl: "incidents?$top=1",
maxRetries: 1,
retryBaseDelayMs: 0,
retryMaxDelayMs: 0
});
const lifecycleEvents = infoLogs
.filter((entry) =>
[
"relay_request_started",
"relay_request_retrying",
"relay_request_succeeded"
].includes(entry[0])
)
.map((entry) => entry[1]);
assert.strictEqual(lifecycleEvents.length, 3);
const relayRequestIds = lifecycleEvents.map(
(event) => event.relayRequestId
);
assert.ok(
relayRequestIds.every((id) => typeof id === "string" && id.length > 0)
);
assert.strictEqual(new Set(relayRequestIds).size, 1);
});
const run = async () => {
let passed = 0;
for (const currentTest of tests) {