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.
This commit is contained in:
Marc-André Bombeck committed 2026-05-17 17:22:10 +02:00
1 parent 4e284235fc
commit 6cbdad5f58
1 file changed
+19 -10
+19 -10
View File
@@ -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,
});
}),
);
}
/**