fix(core): only fall back to the derived hash on a definitive not-found

A transient failure (503, connection error) of the verbatim attempt
leaves that key's state unknown. Issuing the derived-hash reset anyway
is a write against a key the caller may not have targeted, and it
reports success while the verbatim run stays deduplicated. Now only a
404, a definitive miss, unlocks the fallback; any other error surfaces
unchanged, exactly as previous versions behaved.
This commit is contained in:
Matt Aitken
2026-08-19 11:59:32 +01:00
parent fa7634f8c6
commit dc081e578b
2 changed files with 6 additions and 17 deletions
+2 -17
View File
@@ -193,28 +193,13 @@ describe("resetIdempotencyKey", () => {
expect(resetKeys).toEqual([digestShapedKey]);
});
it("falls back to the derived hash when the verbatim attempt fails with a 503", async () => {
it("does not reset the derived run when the verbatim attempt fails transiently", async () => {
const created = await createIdempotencyKey(digestShapedKey, { scope: "global" });
resetIdempotencyKeyCatalog();
statusByKey.set(digestShapedKey, 503);
existingKeys = new Set([created]);
await resetIdempotencyKey(
"my-task",
digestShapedKey,
{ scope: "global" },
{ retry: { maxAttempts: 1 } }
);
expect(resetKeys).toEqual([digestShapedKey, created]);
});
it("surfaces the verbatim attempt's error when it fails with a 503 and the fallback finds nothing", async () => {
const derived = await digestSHA256(digestShapedKey);
statusByKey.set(digestShapedKey, 503);
existingKeys = new Set();
await expect(
resetIdempotencyKey(
"my-task",
@@ -224,7 +209,7 @@ describe("resetIdempotencyKey", () => {
)
).rejects.toMatchObject({ status: 503 });
expect(resetKeys).toEqual([digestShapedKey, derived]);
expect(resetKeys).toEqual([digestShapedKey]);
});
it("surfaces the fallback's error when it fails with something other than a 404", async () => {
+4
View File
@@ -292,6 +292,10 @@ export async function resetIdempotencyKey(
try {
return await client.resetIdempotencyKey(taskIdentifier, idempotencyKey, requestOptions);
} catch (error) {
if (!(error instanceof NotFoundError)) {
throw error;
}
try {
return await client.resetIdempotencyKey(taskIdentifier, hash, requestOptions);
} catch (fallbackError) {