fix(google-health): annotate an ended backfill in one fixed shape

The ended note carried the whole map of ended collections, dates and all,
which duplicated the slice report and gave dashboards no stable shape. It
now names the collection that just ended, its type and reason, whether the
end is final, and counts the ends so far with their types. It stays meta:
the job names the event's action once the slice is over, which would
replace an action set here.
This commit is contained in:
Marc-André Bombeck committed 2026-10-20 03:34:45 +02:00
1 parent bfbd88b30b
commit 7c23a49708
3 files changed
+42 -4

No files matched your search

@@ -9,9 +9,10 @@
*/
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const { prismaMock, safeFetchMock } = vi.hoisted(() => ({
const { prismaMock, safeFetchMock, annotateMock } = vi.hoisted(() => ({
prismaMock: { googleHealthConnection: { update: vi.fn() } },
safeFetchMock: vi.fn(),
annotateMock: vi.fn(),
}));
vi.mock("@/lib/db", () => ({ prisma: prismaMock }));
vi.mock("@/lib/safe-fetch", async (importOriginal) => ({
@@ -19,7 +20,7 @@ vi.mock("@/lib/safe-fetch", async (importOriginal) => ({
safeFetch: safeFetchMock,
}));
vi.mock("@/lib/logging/context", () => ({
annotate: () => {},
annotate: annotateMock,
getEvent: () => null,
}));
@@ -321,6 +322,24 @@ describe("a collection ended short", () => {
expect(googleHealthBackfillProgressAfterCompletion(ended)).toBeNull();
});
it("annotates an end in one fixed shape", async () => {
await slice(stalls, new Map([["fetchWeight", HORIZON_END]]));
const notes = annotateMock.mock.calls
.map(([fields]) => fields.meta?.["googleHealth.backfill.ended"])
.filter(Boolean);
expect(notes).toEqual([
{
collection: "fetchHeartRate",
type: "PULSE",
reason: "no_progress",
final: false,
endedCount: 2,
finalCount: 1,
types: ["PULSE", "WEIGHT"],
},
]);
});
it("is not walked again before its day is up", async () => {
const walk = vi.fn(async () => 1);
const { skipped } = await slice(
+17 -1
View File
@@ -612,8 +612,24 @@ export async function recordGoogleHealthBackfillEnd(
}
: end,
);
// A fixed shape, not the whole note: the slice report carries every end in
// full (`googleHealth.backfill.slice`). This names the one that just ended
// and counts the rest. It is meta, not the event's action, because the job
// names the action once the slice is over and that would replace it.
const recorded = ended.get(key)!;
const final = [...ended.values()].filter(googleHealthBackfillEndIsFinal);
annotate({
meta: { "googleHealth.backfill.ended": Object.fromEntries(ended) },
meta: {
"googleHealth.backfill.ended": {
collection: key,
type: recorded.type,
reason: recorded.reason,
final: googleHealthBackfillEndIsFinal(recorded),
endedCount: ended.size,
finalCount: final.length,
types: [...new Set([...ended.values()].map((e) => e.type))].sort(),
},
},
});
try {
await persistBackfillProgress(resume, {