fix: validate provider retry attempts

This commit is contained in:
Peter Steinberger
2026-05-28 16:28:03 -04:00
parent b1c95a82a0
commit 714ff554fd
2 changed files with 48 additions and 1 deletions

View File

@@ -0,0 +1,44 @@
import { describe, expect, it, vi } from "vitest";
import {
executeProviderOperationWithRetry,
resolveTransientProviderAttempts,
} from "./operation-retry.js";
describe("resolveTransientProviderAttempts", () => {
it("does not round malformed attempt counts", () => {
expect(resolveTransientProviderAttempts({ attempts: 1.5 })).toBe(1);
expect(resolveTransientProviderAttempts({ attempts: Number.NaN })).toBe(1);
expect(resolveTransientProviderAttempts({ attempts: Number.POSITIVE_INFINITY })).toBe(1);
expect(resolveTransientProviderAttempts({ attempts: Number.MAX_SAFE_INTEGER + 1 })).toBe(1);
});
it("keeps valid attempt counts as integers", () => {
expect(resolveTransientProviderAttempts({ attempts: 0 })).toBe(1);
expect(resolveTransientProviderAttempts({ attempts: 3 })).toBe(3);
});
});
describe("executeProviderOperationWithRetry", () => {
it("does not turn fractional attempts into an extra execution", async () => {
const operation = vi.fn(async () => {
const error = new Error("HTTP 503");
Object.assign(error, { status: 503 });
throw error;
});
await expect(
executeProviderOperationWithRetry({
provider: "test",
stage: "read",
operation,
retry: {
attempts: 1.5,
baseDelayMs: 0,
maxDelayMs: 0,
},
}),
).rejects.toThrow("HTTP 503");
expect(operation).toHaveBeenCalledTimes(1);
});
});

View File

@@ -174,7 +174,10 @@ export function resolveTransientProviderAttempts(options?: TransientProviderRetr
if (!options) {
return 1;
}
return Math.max(1, Math.round(Number.isFinite(options.attempts) ? options.attempts : 1));
if (!Number.isSafeInteger(options.attempts)) {
return 1;
}
return Math.max(1, options.attempts);
}
export function resolveTransientProviderDelayMs(