mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 14:40:52 +00:00
chore(release): v1.28.33 — re-importing a cumulative Apple Health export works again
Rollup writes were delete-then-createMany inside a transaction; under READ COMMITTED a concurrent recompute racing the import's full fold on the same (user, type, granularity, bucket, source) partition tripped the composite PK — and the P2002 swallow dropped the loser's freshly computed aggregate, leaving a stale bucket. persistRollupRows now writes chunked INSERT … ON CONFLICT DO UPDATE with deterministic (type, source, bucket) lock ordering inside one transaction: a race can neither fail the import nor lose an aggregate, and previously-staled buckets self-heal on their next recompute. The vanished-source delete and in-transaction guarantees are preserved; the now-unreachable P2002 swallow is removed. The masked ENOENT is gone with it: long imports outlived the queue's 15-minute expiry, pg-boss redelivered the still-running job, and the redelivery re-opened the consumed staging file — overwriting the real terminal state with a raw ENOENT. Import sends now carry retryLimit 0 + 6h expiry (a retry after the staging file is consumed can only mask), deliveries for terminal ImportJob rows are no-ops, a genuinely missing staging file reports an honest re-upload message, and the extracted XML is cleaned up on failure too.
This commit is contained in:
1 parent
5b7ea48c46
commit
6d8fe06148
12 files changed
+902
-157
No files matched your search
@@ -22,6 +22,7 @@ import { checkRateLimit } from "@/lib/rate-limit";
|
||||
import { getGlobalBoss } from "@/lib/jobs/boss-instance";
|
||||
import {
|
||||
APPLE_HEALTH_IMPORT_QUEUE,
|
||||
APPLE_HEALTH_IMPORT_SEND_OPTIONS,
|
||||
type AppleHealthImportPayload,
|
||||
} from "@/lib/jobs/apple-health-import-worker";
|
||||
import { streamMultipartToDisk } from "@/lib/multipart/stream-to-disk";
|
||||
@@ -158,7 +159,14 @@ export const POST = apiHandler(async (request: NextRequest) => {
|
||||
uploadBytes: uploaded.bytes,
|
||||
enqueuedAt: new Date().toISOString(),
|
||||
};
|
||||
const bossJobId = await boss.send(APPLE_HEALTH_IMPORT_QUEUE, payload);
|
||||
// No retries + wide expiration: the staged upload is consumed by the
|
||||
// first run, so a redelivery could only fail on the deleted `/tmp`
|
||||
// file and mask the real outcome (see the worker's send-options doc).
|
||||
const bossJobId = await boss.send(
|
||||
APPLE_HEALTH_IMPORT_QUEUE,
|
||||
payload,
|
||||
APPLE_HEALTH_IMPORT_SEND_OPTIONS,
|
||||
);
|
||||
|
||||
await prisma.importJob.update({
|
||||
where: { id: importJob.id },
|
||||
|
||||
Reference in new issue
Block a user