mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 13:22:14 +00:00
Merge w11/perf into release/v1.18.11
Serve achievements via SWR and precompute Berlin day-keys to kill the per-row Intl cost; switch dashboard/summary to cachedSwr; lazy-load three charts that bypassed the dynamic boundary.
This commit is contained in:
commit
6975849bec
10 files changed
+357
-35
No files matched your search
@@ -55,7 +55,7 @@ import { CUMULATIVE_HK_TYPES } from "@/lib/measurements/apple-health-mapping";
|
||||
import { getServerTranslator } from "@/lib/i18n/server-translator";
|
||||
import { defaultLocale, locales, type Locale } from "@/lib/i18n/config";
|
||||
import { userDayKey, DEFAULT_TIMEZONE } from "@/lib/tz/resolver";
|
||||
import { cached, caches, type ServerCache } from "@/lib/cache/server-cache";
|
||||
import { cachedSwr, caches, type ServerCache } from "@/lib/cache/server-cache";
|
||||
import { buildMedsTodayBlock } from "@/lib/dashboard/meds-today";
|
||||
import {
|
||||
summarizeSleepNights,
|
||||
@@ -328,12 +328,23 @@ export const GET = apiHandler(async () => {
|
||||
// it).
|
||||
const userTz = user.timezone ?? DEFAULT_TIMEZONE;
|
||||
|
||||
// v1.4.38 W-F — wrap the whole response in the 60 s analytics LRU.
|
||||
// v1.4.38 W-F — wrap the whole response in the analytics LRU.
|
||||
// Subsequent iOS polls inside the TTL hit memory; measurement /
|
||||
// mood / medication writes invalidate the user-bucket via the
|
||||
// existing `invalidateUserMeasurements` + the v1.4.38-extended
|
||||
// `invalidateUserMedications` hooks.
|
||||
const body = await cached(
|
||||
//
|
||||
// v1.18.11 (W5 perf) — read via `cachedSwr`. The `analytics` bucket
|
||||
// already provisions a 1 h `staleTtlMs` window, but this endpoint read
|
||||
// through plain `cached` and so ignored it: the iOS client polls every
|
||||
// 60 s, and a plain read past the 60 s fresh TTL re-paid the full cold
|
||||
// rebuild on every poll. `cachedSwr` serves the prior body instantly
|
||||
// inside the stale window and warms one background recompute instead.
|
||||
// Writes still mark/evict the bucket, so a user's own action is
|
||||
// reflected on the very next read — the window only bounds wall-clock
|
||||
// drift (the same self-correcting `nextDueOverdue`/tally drift the
|
||||
// snapshot read already tolerates).
|
||||
const body = await cachedSwr(
|
||||
caches.analytics as ServerCache<
|
||||
Awaited<ReturnType<typeof buildDashboardSummary>>
|
||||
>,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { apiHandler, requireAuth } from "@/lib/api-handler";
|
||||
import { requireModuleEnabled, resolveModuleMap } from "@/lib/modules/gate";
|
||||
import { annotate } from "@/lib/logging/context";
|
||||
import { apiSuccess } from "@/lib/api-response";
|
||||
import { cached, caches, type ServerCache } from "@/lib/cache/server-cache";
|
||||
import { cachedSwr, caches, type ServerCache } from "@/lib/cache/server-cache";
|
||||
import {
|
||||
buildAchievementsResult,
|
||||
type AchievementsResult,
|
||||
@@ -72,7 +72,13 @@ export const GET = apiHandler(async (request: NextRequest) => {
|
||||
// a toggle change is reflected on the next read.
|
||||
const moduleMap = await resolveModuleMap(user.id);
|
||||
|
||||
const result = await cached(
|
||||
// v1.18.11 (W5 perf) — read via `cachedSwr`. The bucket carries a
|
||||
// 10-minute stale window; the app-wide `AchievementUnlockNotifier` polls
|
||||
// every 2 minutes, so a hard-TTL read always missed and re-paid the cold
|
||||
// build. SWR serves the prior payload instantly and warms one background
|
||||
// recompute. Persistence of `pendingUnlocks` stays OUTSIDE this read (see
|
||||
// below), so a stale-served body never skips an unlock write.
|
||||
const result = await cachedSwr(
|
||||
caches.achievements as ServerCache<AchievementsResult>,
|
||||
user.id,
|
||||
() => buildAchievementsResult(user, moduleMap),
|
||||
|
||||
Reference in new issue
Block a user