diff --git a/src/lib/day/load-day.ts b/src/lib/day/load-day.ts index ae97357ee..0d517c770 100644 --- a/src/lib/day/load-day.ts +++ b/src/lib/day/load-day.ts @@ -14,6 +14,8 @@ * once in `sections`. Nothing here writes, and nothing here talks to a model; * `model-projection.ts` is the one way a day leaves for one. */ +import pLimit from "p-limit"; + import type { MeasurementType } from "@/generated/prisma/enums"; import { readDayMovement } from "@/lib/dawarich/movement"; @@ -35,6 +37,9 @@ import { loadUserSourcePriority } from "@/lib/rollups/measurement-read"; import { localDayWindow } from "@/lib/tz/local-day"; import { resolveUserTimezone } from "@/lib/tz/resolver"; +/** Record sections read at once for one day (see `loadDay`). */ +const DAY_SECTION_CONCURRENCY = 6; + const NO_READINGS: DayReadings = { rowsByType: new Map(), night: null, @@ -99,6 +104,7 @@ export async function loadDay(args: LoadDayArgs): Promise { ? await loadUserSourcePriority(recordId) : null; + const sectionLimit = pLimit(DAY_SECTION_CONCURRENCY); const recordSections = [...access.readable].filter( (section) => RECORD_SECTION_READERS[section] !== undefined, ); @@ -115,13 +121,20 @@ export async function loadDay(args: LoadDayArgs): Promise { priority, ) : Promise.resolve(NO_READINGS), + // About twenty-five section readers, each a query or two, beside the + // readings, scores and movement: unbounded they took more connections + // than the pool holds, and a neighbouring request waited for a slot. + // Six at a time keeps the day under a third of the pool; the parts come + // back in section order as before. Promise.all( recordSections.map((section) => - ( - RECORD_SECTION_READERS[section] as ( - frame: DayFrame, - ) => Promise - )(frame), + sectionLimit(() => + ( + RECORD_SECTION_READERS[section] as ( + frame: DayFrame, + ) => Promise + )(frame), + ), ), ), scoresReadable