Let an upgraded binary start against the settings it wrote before
The deployed service crash-looped 83 times on "config.toml:3: unknown setting \"include_amount\"". The classification redesign retired that preference from both the reader and the writer, but /var/lib/finance-duck/config.toml was written by the previous binary and still names it, and Open refuses any key its switch does not recognise. So the new binary would not start against its own settings file: nixos-rebuild switched successfully, systemd restarted the unit until it gave up, and the updater's health check failed - a deployment error whose cause was neither the build nor the code that was deployed. Retired settings are now read and discarded, and the next SaveSettings rewrites the file without them. An unrecognised key is still refused, because a misspelled preference that loads silently is a preference the user believes is in force. Every future removal adds its key to the same list rather than stranding the deployments that already hold it. Verified by running the built binary against a config.toml carrying exactly the line the host has: it starts and /api/health answers 200, where the previous binary exited 1. The regression test fails with "retired setting must not stop startup" before the change, and it still requires classify_on_imports to be rejected.
This commit is contained in:
+10
-1
@@ -79,6 +79,13 @@ type App struct {
|
||||
syncRequested chan struct{}
|
||||
}
|
||||
|
||||
// Settings this application has retired. They are read and discarded: a
|
||||
// config.toml written by an older binary must never stop the new one from
|
||||
// starting, and the next SaveSettings rewrites the file without them. An
|
||||
// unrecognised key is still refused, so a typo cannot silently lose a
|
||||
// preference.
|
||||
var retiredSettings = map[string]bool{"include_amount": true}
|
||||
|
||||
func Open(dir string) (*App, error) {
|
||||
j, err := journal.Open(dir)
|
||||
if err != nil {
|
||||
@@ -115,7 +122,9 @@ func Open(dir string) (*App, error) {
|
||||
case "classify_on_import":
|
||||
a.settings.ClassifyOnImport, err = strconv.ParseBool(v)
|
||||
default:
|
||||
err = fmt.Errorf("unknown setting %q", k)
|
||||
if !retiredSettings[k] {
|
||||
err = fmt.Errorf("unknown setting %q", k)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fail(fmt.Errorf("config.toml:%d: %w", n+1, err))
|
||||
|
||||
Reference in New Issue
Block a user