fix(google-health): count only retries that end at the same edge

A collection parked after a walk without progress is walked again a day
later. Its attempt count went up on every later end without progress, even
when the retry had reached further back before it stalled again, so a
history that kept moving in short steps was declared ended after two
attempts. The count now carries the edge it was parked at and starts over
at one when the new end lies elsewhere.
This commit is contained in:
Marc-André Bombeck committed 2026-10-20 00:55:53 +02:00
1 parent 8eb4ef3d56
commit acdea22e2b
2 files changed
+41 -7

No files matched your search

@@ -351,6 +351,31 @@ describe("a collection ended short", () => {
).toMatchObject({ ...END, attempts: 2 });
});
it("starts the count over when the retry got further back before it stalled again", async () => {
const further = { ...END, at: "2023-01-02T00:00:00.000Z" };
const done = new Set<string>();
const { ended, collections } = await slice(
async () => {
noteGoogleHealthDeferred();
await recordGoogleHealthBackfillEnd("fetchHeartRate", further);
return 4;
},
new Map<string, GoogleHealthBackfillEnd>([
["fetchHeartRate", parked(1, 25)],
]),
done,
);
// Progress, then a new stall: parked again, not final.
expect(ended.get("fetchHeartRate")).toMatchObject({
...further,
attempts: 1,
});
expect(done.has("fetchHeartRate")).toBe(false);
expect(collections).toEqual([
expect.objectContaining({ key: "fetchHeartRate", status: "stopped" }),
]);
});
it("goes back to an ordinary walk when the second attempt gets somewhere", async () => {
const { ended, collections } = await slice(
async () => {
+16 -7
View File
@@ -497,9 +497,10 @@ interface BackfillResumeTracker {
ended: Map<string, GoogleHealthBackfillEnd>;
/**
* Collections walked again this attempt after an earlier one ended without
* progress, with how many attempts had ended that way.
* progress, with how many attempts in a row had ended that way and the edge
* they ended at.
*/
retrying: Map<string, number>;
retrying: Map<string, { attempts: number; at: string }>;
}
const backfillResumeStorage = new AsyncLocalStorage<BackfillResumeTracker>();
@@ -857,14 +858,18 @@ export async function recordGoogleHealthBackfillEnd(
const resume = backfillResumeStorage.getStore();
if (!resume) return;
const ended = new Map(resume.ended);
// Counted across attempts that end at the same edge: a walk that got
// further back before it stalled again made progress, and its count starts
// over. Only attempts in a row that reach nowhere make the end final.
const parked = resume.retrying.get(key);
const sameEdge =
parked !== undefined && Date.parse(parked.at) === Date.parse(end.at);
ended.set(
key,
end.reason === "no_progress"
? {
...end,
// Counted across attempts: the one walked again this attempt
// carries the count it was parked with.
attempts: (resume.retrying.get(key) ?? 0) + 1,
attempts: sameEdge ? parked.attempts + 1 : 1,
endedAt: new Date().toISOString(),
}
: end,
@@ -1073,8 +1078,12 @@ export async function runGoogleHealthCollection(
if (parked) {
// Its earlier attempt ended without progress and its wait is over: walk
// it again from its edge. The note goes with the next write; the count
// stays with the attempt, so a second end without progress is final.
resume.retrying.set(key, parked.attempts ?? 1);
// and the edge stay with the attempt, so a second end at the same edge
// is final.
resume.retrying.set(key, {
attempts: parked.attempts ?? 1,
at: parked.at,
});
resume.ended.delete(key);
}
const startedAt = performance.now();