mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
refactor(insights): extract shared timeout-stub persist helper
Pull the 40-line auditLog.create block out of bmi-status into a dedicated `persist-timeout-stub.ts` helper so every InsightStatus route can share one persist path instead of copy-pasting the sentinel-row shape. The bmi route now calls the helper in a 6-line return; behaviour and persisted body are byte-equivalent to the inline form. Sets up the next commit, which wires the six remaining sibling routes (blood-pressure, weight, general, pulse, mood, medication-compliance) to the same helper and closes the last bare-fallback shape on the dashboard hot path.
This commit is contained in:
1 parent
cd2a579cc3
commit
e4d46de22d
2 files changed
+83
-43
No files matched your search
@@ -13,6 +13,7 @@ import {
|
||||
withTimeout,
|
||||
STATUS_PROVIDER_TIMEOUT_MS,
|
||||
} from "@/lib/insights/with-timeout";
|
||||
import { persistTimeoutStubAndReturn } from "@/lib/insights/persist-timeout-stub";
|
||||
import { annotate } from "@/lib/logging/context";
|
||||
|
||||
const BERLIN_DAY_FORMATTER = new Intl.DateTimeFormat("en-US", {
|
||||
@@ -294,49 +295,15 @@ export async function generateBmiStatusForUser(
|
||||
// v1.4.37 — persist a sentinel row keyed to today so the next
|
||||
// mount short-circuits at the cache lookup above instead of
|
||||
// re-racing the same 20 s provider call on every cold visit.
|
||||
// Without this, a single stall (provider hiccup, network blip,
|
||||
// model warm-up) leaves the user staring at the loading state
|
||||
// on every reload until the daily 02:20 pre-warm job runs.
|
||||
// The body is the same no-key fallback the caller returned
|
||||
// before, so the user-facing UI is identical; only the
|
||||
// re-fire frequency drops to zero for the rest of the day.
|
||||
// `meta.timeout` is set so the daily pg-boss pre-warm worker
|
||||
// (the same job that originally seeded the cache) can
|
||||
// recognise and overwrite the stub rather than respect it as
|
||||
// a real assessment.
|
||||
const stubText = getNoKeyBmiStatusText(locale);
|
||||
let stubUpdatedAt: string | null = null;
|
||||
try {
|
||||
const stub = await prisma.auditLog.create({
|
||||
data: {
|
||||
userId,
|
||||
action: cacheAction,
|
||||
details: JSON.stringify({
|
||||
dateKey: todayKey,
|
||||
locale,
|
||||
text: stubText,
|
||||
providerType: provider.type,
|
||||
model: "timeout-stub",
|
||||
tokensUsed: null,
|
||||
timeout: true,
|
||||
}),
|
||||
},
|
||||
select: { createdAt: true },
|
||||
});
|
||||
stubUpdatedAt = stub.createdAt.toISOString();
|
||||
} catch {
|
||||
// The persist is best-effort — if the row write fails the
|
||||
// caller still sees the deterministic fallback text and the
|
||||
// next mount falls back to the (still expensive) race. Do
|
||||
// not surface the error: the user does not care that the
|
||||
// cache write missed, only that the page rendered.
|
||||
}
|
||||
return {
|
||||
hasProvider: true,
|
||||
text: stubText,
|
||||
cached: true,
|
||||
updatedAt: stubUpdatedAt,
|
||||
};
|
||||
// See `persistTimeoutStubAndReturn` for the full rationale.
|
||||
return persistTimeoutStubAndReturn({
|
||||
userId,
|
||||
cacheAction,
|
||||
todayKey,
|
||||
locale,
|
||||
providerType: provider.type,
|
||||
stubText: getNoKeyBmiStatusText(locale),
|
||||
});
|
||||
}
|
||||
|
||||
const result = raced.value;
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import { prisma } from "@/lib/db";
|
||||
|
||||
/**
|
||||
* v1.4.37 / v1.4.41 — shared timeout-stub persist for InsightStatus routes.
|
||||
*
|
||||
* When the upstream provider call exceeds `STATUS_PROVIDER_TIMEOUT_MS`
|
||||
* the caller persists a sentinel `auditLog` row keyed to today's Berlin
|
||||
* day so the next mount short-circuits at the cache lookup instead of
|
||||
* re-racing the same 20 s provider call on every cold visit. Without
|
||||
* this, a single stall (provider hiccup, network blip, model warm-up)
|
||||
* leaves the user staring at the loading state on every reload until
|
||||
* the daily 02:20 pre-warm job runs.
|
||||
*
|
||||
* The persisted body is the deterministic no-key fallback the caller
|
||||
* would have returned in the bare-fallback shape, so the user-facing
|
||||
* UI is identical; only the re-fire frequency drops to zero for the
|
||||
* rest of the day.
|
||||
*
|
||||
* `meta.timeout` + `meta.model = "timeout-stub"` are set so the daily
|
||||
* pg-boss pre-warm worker (the same job that originally seeded the
|
||||
* cache) can recognise and overwrite the stub rather than respect it
|
||||
* as a real assessment.
|
||||
*
|
||||
* The write is best-effort — if it fails the caller still sees the
|
||||
* deterministic fallback text and the next mount falls back to the
|
||||
* (still expensive) race. We do not surface the error: the user does
|
||||
* not care that the cache write missed, only that the page rendered.
|
||||
*/
|
||||
export async function persistTimeoutStubAndReturn(input: {
|
||||
userId: string;
|
||||
cacheAction: string;
|
||||
todayKey: string;
|
||||
locale: string;
|
||||
providerType: string;
|
||||
stubText: string;
|
||||
}): Promise<{
|
||||
hasProvider: true;
|
||||
text: string;
|
||||
cached: true;
|
||||
updatedAt: string | null;
|
||||
}> {
|
||||
const { userId, cacheAction, todayKey, locale, providerType, stubText } =
|
||||
input;
|
||||
let stubUpdatedAt: string | null = null;
|
||||
try {
|
||||
const stub = await prisma.auditLog.create({
|
||||
data: {
|
||||
userId,
|
||||
action: cacheAction,
|
||||
details: JSON.stringify({
|
||||
dateKey: todayKey,
|
||||
locale,
|
||||
text: stubText,
|
||||
providerType,
|
||||
model: "timeout-stub",
|
||||
tokensUsed: null,
|
||||
timeout: true,
|
||||
}),
|
||||
},
|
||||
select: { createdAt: true },
|
||||
});
|
||||
stubUpdatedAt = stub.createdAt.toISOString();
|
||||
} catch {
|
||||
// The persist is best-effort — silently swallow so the user-facing
|
||||
// payload still renders even when the row write missed.
|
||||
}
|
||||
return {
|
||||
hasProvider: true,
|
||||
text: stubText,
|
||||
cached: true,
|
||||
updatedAt: stubUpdatedAt,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user