chore(release): v1.28.36 — re-importing after a failed Apple Health import actually retries

The v1.28.33 rollup + staging fixes were correct but never reached the
reporter's case: the upload dedup keys on the content SHA-256 and the
lookup matched a previously FAILED job too, so re-uploading the same
export.zip returned the dead job's id and replayed its stale
failureReason without ever staging or sending again. The dedup now
excludes failed rows (short-circuits only on queued/unpacking/parsing/
upserting/done); the same bytes retry cleanly. A redundant staged upload
is unlinked on a dedup hit instead of leaking in the staging dir.

reconcileOrphanImportJobs no longer unconditionally fails every
non-terminal ImportJob at boot: it now checks pg-boss job state plus a
progress heartbeat (new import_jobs.updated_at, migration 0242), so a
split or multi-worker deployment cannot kill an import running in
another worker. The missing-staging message names the separate-container
cause explicitly, with a matching note in docs/self-hosting/scaling.md.
This commit is contained in:
Marc-André Bombeck committed 2026-07-15 22:07:25 +02:00
1 parent a614542cc3
commit 82aa66b400
13 files changed
+590 -19

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
openapi: 3.1.0
info:
title: HealthLog API
version: 1.28.35
version: 1.28.36
description: >-
Self-hosted personal-health-tracking PWA — public API surface for the iOS native client and external ingest.
+26
View File
@@ -30,6 +30,32 @@ but it doubles the DB load and muddies telemetry without adding
throughput a personal instance needs (`src/lib/process-type.ts`).
Run **one** worker container and scale the `web` containers instead.
## Apple Health import staging (shared volume required for a split)
The Apple Health `export.zip` import streams the upload to a staging
file on local disk (under the container's temp dir) and hands the
worker only the file **path**. In single-container mode
(`HEALTHLOG_PROCESS_TYPE=all`, the default) the web handler and the
worker share the same filesystem, so the handoff just works.
In a web/worker split — or any topology where the container that
accepts the upload is not the one that runs the job (a `web` +
`worker` split, extra `all` replicas, or old+new containers coexisting
during a rolling deploy) — the worker cannot see the web container's
staging file. The import then fails with a staging-file-missing error
("the import staging file is not visible to the worker"). Two things to
know:
- A pure `web` container has no pg-boss handle, so an import kicked off
there currently returns `503 Background worker is not running`. Run
imports from a container that also runs the worker until send-only
boss support lands.
- If you run web and worker as separate containers, they **must share
the import staging directory** — mount the same named volume at the
temp path on both — or run imports in single-container (`all`) mode.
Without a shared staging volume, imports in split mode cannot
complete.
## Healthchecks
- `app` (web) healthcheck: `wget /api/version` every 30s.