Skip to content

Replace settings.json rather than rewriting it in place - #820

Merged
SimonCropp merged 2 commits into
mainfrom
fix-settings-atomic-write
Aug 22, 2026
Merged

Replace settings.json rather than rewriting it in place#820
SimonCropp merged 2 commits into
mainfrom
fix-settings-atomic-write

Conversation

@SimonCropp

Copy link
Copy Markdown
Member

Write deleted the file and then opened it again to serialise into, so between the
two there was no settings.json at all, and until the serialise finished there was a
partial one. A kill anywhere in there - a logoff, a reboot, task manager - left the
tray meeting "Cannot start. Failed to read settings" at every launch afterwards,
with deleting the file by hand the only way out.

It is now serialised beside the file and moved over it, so the live path only ever
holds a whole document.

The swap can lose a race with anything holding the file open, which the old delete
could not, so it is retried for a fifth of a second before giving up. That path used
to throw straight out of an async void click handler.

WriteFile is the file half on its own. Write also persists two User scope
environment variables, a registry write and a broadcast each, which the test that
hammers this would spend all its time on.

Write deleted the file and then opened it again to serialise into, so between the
two there was no settings.json at all, and until the serialise finished there was a
partial one. A kill anywhere in there - a logoff, a reboot, task manager - left the
tray meeting "Cannot start. Failed to read settings" at every launch afterwards,
with deleting the file by hand the only way out.

It is now serialised beside the file and moved over it, so the live path only ever
holds a whole document.

The swap can lose a race with anything holding the file open, which the old delete
could not, so it is retried for a fifth of a second before giving up. That path used
to throw straight out of an async void click handler.

WriteFile is the file half on its own. Write also persists two User scope
environment variables, a registry write and a broadcast each, which the test that
hammers this would spend all its time on.
It reopened settings.json the instant it closed it, so it held the file for most of
the time it ran. On the two core Windows runner that starved the swap of all eleven
attempts it has and failed the test on the writer's side, which is the test being an
adversary no real reader is.

It now looks once a millisecond, and runs until it has looked a hundred times rather
than for a fixed number of writes, so the number of independent samples does not
depend on how fast the machine writes. A missing file is counted as a look too -
without that the run ended on the write cap with too few looks to assert on, and the
unfixed write failed on the guard rather than on what it was there to catch.
@SimonCropp SimonCropp added this to the 20.0.0 milestone Aug 22, 2026
@SimonCropp
SimonCropp merged commit 3978efd into main Aug 22, 2026
9 checks passed
@SimonCropp
SimonCropp deleted the fix-settings-atomic-write branch August 22, 2026 12:07
This was referenced Aug 26, 2026
This was referenced Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant