From 6cbdad5f58c0a8b2da95a8699eea095c613ef4da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 17 May 2026 17:22:10 +0200 Subject: [PATCH] perf(rollups): parallel WEEK/MONTH/YEAR enqueue on measurement write `recomputeBucketsForMeasurement` enqueued the three async-granularity recomputes in a serial `for-of` loop. Each enqueue is independent (different pg-boss singletonKey per granularity) so the await chain adds three sequential round-trips to the post-write critical path on every measurement create / update / delete. Replace the loop with `Promise.all` so the three enqueues fan out at once. Matters on iOS batch imports that fire hundreds of hooks back-to-back. --- src/lib/measurements/rollups.ts | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/lib/measurements/rollups.ts b/src/lib/measurements/rollups.ts index faee36a83..c596a8ed1 100644 --- a/src/lib/measurements/rollups.ts +++ b/src/lib/measurements/rollups.ts @@ -199,16 +199,25 @@ export async function recomputeBucketsForMeasurement( // WEEK / MONTH / YEAR — enqueue. Each granularity covers a range // around the affected day so the worker only re-aggregates the // bucket(s) the write could have changed. - for (const granularity of ASYNC_GRANULARITIES) { - const { from, to } = bucketSpan(measuredAt, granularity); - await enqueueRollupRecompute({ - userId, - type, - granularity, - from, - to, - }); - } + // + // v1.4.38 — the three `enqueueRollupRecompute` calls are independent + // (different singletonKey per granularity inside `enqueueRollupRecompute`) + // so fan them out via `Promise.all` instead of sequencing them with + // `await`. Halves the post-write critical path on every measurement + // create / update / delete; matters on iOS batch imports that fire + // hundreds of hooks back-to-back. + await Promise.all( + ASYNC_GRANULARITIES.map((granularity) => { + const { from, to } = bucketSpan(measuredAt, granularity); + return enqueueRollupRecompute({ + userId, + type, + granularity, + from, + to, + }); + }), + ); } /**