forgejo: restart the db service on a clean exit, not just on failure #128
No reviewers
Labels
No labels
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: Jinemi/thermograph#128
Loading…
Reference in a new issue
No description provided.
Delete branch "forgejo-db-restart-policy"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What happened
forgejo_dbsat at 0/1 replicas from 2026-07-29 01:24 UTC until 2026-07-30, roughly 27 hours.Postgres hit an invalid data-directory lock file:
…and exited 0. With
restart_policy.condition: on-failure, Swarm read that zero status as successful completion, marked the taskComplete, dropped the service to 0 replicas, and never rescheduled it.Why it was hard to spot
The
forgejoservice itself stayed1/1 Upand kept serving its homepage, so/returned 200 the whole time. Everything needing the database returned 500:dial tcp: lookup db on 127.0.0.11:53: no such hostThe auth path failed the same way, which made API calls report
401 {"message":"user does not exist [uid: 0, name: ]"}— Forgejo could not read its own user table. That misleadingly looks like an expired token, and was initially diagnosed as one.CENTRALIS_FORGEJO_TOKENwas never expired and needed no rotation.The fix
condition: anywith a 5s delay.on-failurecannot distinguish "finished successfully" from "shut itself down and should be restarted", and Postgres exits 0 on several such paths. It is the wrong policy for any always-on stateful service.This is the durable fix only — it prevents recurrence but does not itself recover a database. Recovery was separate: the data directory's WAL was unrecoverable (
invalid contrecord length,invalid checkpoint record,PANIC: could not locate a valid checkpoint record), so the service was restored from the2026-07-28T03:00Zoff-box dump. The corrupt data directory is preserved byte-for-byte in theforgejo_db_corrupt_20260730volume on vps1, withpg_controlandpg_walintact, in case apg_resetwalattempt to recover the intervening ~22 hours of metadata is ever wanted.Follow-ups this exposed, not addressed here
on-failurepolicy should be audited on every other stateful service in the estate's stack files.forgejo-backupjob needs a liveforgejo_dbtopg_dump, so there are nobackups/forgejo/db/objects dated 07-29 or 07-30. A backup job that cannot find its source should fail loudly rather than leave a gap.forgejo_db has been at 0/1 replicas since 2026-07-29 01:24 UTC. Postgres hit an invalid data-directory lock file ("could not open file postmaster.pid ... performing immediate shutdown because data directory lock file is invalid") and exited 0. With restart_policy.condition=on-failure, Swarm read the zero status as successful completion, marked the task Complete, and never rescheduled it. The forgejo service itself stayed Up and kept serving its homepage, so the outage presented as every repository page, the whole API and all CI returning 500 with "dial tcp: lookup db on 127.0.0.11:53: no such host" — including the auth path, which is why API calls reported "user does not exist [uid: 0]" rather than a database error. on-failure cannot distinguish "finished successfully" from "shut itself down and should be restarted", and Postgres exits 0 on several such paths, so it is the wrong policy for an always-on stateful service. This is the durable fix; it does not restart the currently stopped task.