mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
feat(mood-rollups): boot-time backfill queue for legacy accounts
Registers mood-rollup-recompute (per-bucket WEEK/MONTH/YEAR fold) and mood-rollup-full-backfill (boot discovery) onto pg-boss. The worker boot now fires a discovery query that enqueues one full-fold job per user with mood entries but zero mood_entry_rollups rows — idempotent across reboots and singleton-keyed so a fast restart while a backfill is queued doesn't double up. Legacy accounts pre-dating the v1.4.39 deploy auto-converge on the persistent tier without operator action.
This commit is contained in:
1 parent
1c6264dfd3
commit
d15850d526
1 file changed
+100
@@ -67,6 +67,16 @@ import {
|
||||
type RollupFullBackfillPayload,
|
||||
type RollupRecomputePayload,
|
||||
} from "@/lib/measurements/rollups";
|
||||
import {
|
||||
MOOD_ROLLUP_FULL_BACKFILL_QUEUE,
|
||||
MOOD_ROLLUP_FULL_BACKFILL_CONCURRENCY,
|
||||
MOOD_ROLLUP_RECOMPUTE_QUEUE,
|
||||
MOOD_ROLLUP_RECOMPUTE_CONCURRENCY,
|
||||
enqueueBootTimeMoodRollupBackfill,
|
||||
recomputeUserMoodRollups,
|
||||
type MoodRollupFullBackfillPayload,
|
||||
type MoodRollupRecomputePayload,
|
||||
} from "@/lib/mood/rollups";
|
||||
import {
|
||||
drainPerSampleCumulative,
|
||||
DRAIN_CUMULATIVE_CUTOFF_HOURS,
|
||||
@@ -1655,6 +1665,17 @@ export async function startReminderWorker() {
|
||||
APPLE_HEALTH_IMPORT_QUEUE,
|
||||
ROLLUP_RECOMPUTE_QUEUE,
|
||||
ROLLUP_FULL_BACKFILL_QUEUE,
|
||||
// v1.4.39 W-MOOD — per-bucket WEEK/MONTH/YEAR fold queue for the
|
||||
// mood rollup tier. The DAY pass runs inline in the write hook;
|
||||
// these enqueue paths cover the cross-granularity buckets the
|
||||
// worker materialises off the request path.
|
||||
MOOD_ROLLUP_RECOMPUTE_QUEUE,
|
||||
// v1.4.39 W-MOOD — boot-time fold queue for the mood rollup tier.
|
||||
// Mirrors the measurement-rollup full-backfill semantics: the
|
||||
// discovery query enqueues one full-fold per user with mood
|
||||
// entries but no rollup rows; the user drops off the list once
|
||||
// the fold completes.
|
||||
MOOD_ROLLUP_FULL_BACKFILL_QUEUE,
|
||||
// v1.4.37 W7c — explicit createQueue is required before the
|
||||
// nightly schedule below registers (pg-boss v12 contract). Without
|
||||
// this entry the drain schedule silently no-ops and the
|
||||
@@ -1916,6 +1937,58 @@ export async function startReminderWorker() {
|
||||
},
|
||||
);
|
||||
|
||||
// v1.4.39 W-MOOD — mood-rollup per-bucket worker. Folds the
|
||||
// WEEK / MONTH / YEAR buckets that the mood-entry write hooks
|
||||
// enqueue; the DAY bucket runs synchronously in the hook itself.
|
||||
// No current read path consumes these buckets — they exist so a
|
||||
// future cross-granularity reader can ship without a backfill
|
||||
// step. Concurrency-2 mirrors the measurement-rollup worker.
|
||||
await boss.work<MoodRollupRecomputePayload>(
|
||||
MOOD_ROLLUP_RECOMPUTE_QUEUE,
|
||||
{ localConcurrency: MOOD_ROLLUP_RECOMPUTE_CONCURRENCY },
|
||||
async (jobs) => {
|
||||
for (const job of jobs) {
|
||||
const payload = job.data;
|
||||
await recomputeUserMoodRollups(payload.userId, {
|
||||
granularities: [payload.granularity],
|
||||
from: new Date(payload.from),
|
||||
to: new Date(payload.to),
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// v1.4.39 W-MOOD — mood-rollup boot-time fold worker. The boot
|
||||
// discovery helper below sends one job per user with mood entries
|
||||
// but zero rollup rows; this handler folds the full 5-year window
|
||||
// across every granularity. Concurrency-1 so the populator never
|
||||
// crowds the request pool.
|
||||
await boss.work<MoodRollupFullBackfillPayload>(
|
||||
MOOD_ROLLUP_FULL_BACKFILL_QUEUE,
|
||||
{ localConcurrency: MOOD_ROLLUP_FULL_BACKFILL_CONCURRENCY },
|
||||
async (jobs) => {
|
||||
for (const job of jobs) {
|
||||
const { userId } = job.data;
|
||||
try {
|
||||
const { rowsUpserted, durationMs } =
|
||||
await recomputeUserMoodRollups(userId);
|
||||
workerLog(
|
||||
"info",
|
||||
`[mood-rollup-full-backfill] user=${userId} rows=${rowsUpserted} duration=${durationMs}ms`,
|
||||
);
|
||||
} catch (err) {
|
||||
recordError();
|
||||
workerLog(
|
||||
"error",
|
||||
`[mood-rollup-full-backfill] user=${userId} failed`,
|
||||
err,
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// v1.4.37 W7c — nightly drain worker. Walks every user × cumulative
|
||||
// type and folds per-sample APPLE_HEALTH rows older than the cutoff
|
||||
// into one `stats:…` row per calendar day. Idempotent — a second run
|
||||
@@ -1980,6 +2053,33 @@ export async function startReminderWorker() {
|
||||
);
|
||||
}
|
||||
|
||||
// v1.4.39 W-MOOD — fire-and-forget boot discovery for the mood
|
||||
// rollup tier. Mirrors the v1.4.35.1 measurement-rollup pattern:
|
||||
// one job per user with mood entries but no rollup coverage.
|
||||
// Idempotent across reboots and singleton-keyed inside pg-boss so
|
||||
// a fast restart while a backfill is queued doesn't double up.
|
||||
try {
|
||||
const { enqueued, skipped, error } =
|
||||
await enqueueBootTimeMoodRollupBackfill();
|
||||
if (error) {
|
||||
workerLog(
|
||||
"error",
|
||||
`[mood-rollup-full-backfill] boot discovery failed: ${error}`,
|
||||
);
|
||||
} else {
|
||||
workerLog(
|
||||
"info",
|
||||
`[mood-rollup-full-backfill] boot discovery: enqueued=${enqueued} skipped=${skipped}`,
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
workerLog(
|
||||
"error",
|
||||
"[mood-rollup-full-backfill] boot discovery threw an unexpected error",
|
||||
err,
|
||||
);
|
||||
}
|
||||
|
||||
return boss;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user