From 8f32c6c670afe487d66a8f92e0a8538b42ab04af Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Thu, 27 Aug 2026 12:51:31 +0200 Subject: [PATCH] contest: faker: write combined infos atomically The contest service was unable to load the 'branch_info' input file twice recently. Probably because it was being updated: json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0) Instead of catching the error and retry later, this file can be written atomically by using a tmp file and renaming it to the expected name. That's the recommended way [1]: os.rename(src, dst, *, src_dir_fd=None, dst_dir_fd=None): (...) If both are files, dst will be replaced silently if the user has permission. (...) If successful, the renaming will be an atomic operation (this is a POSIX requirement). Link: https://docs.python.org/3/library/os.html#os.rename [1] Signed-off-by: Matthieu Baerts --- contest/results-faker.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contest/results-faker.py b/contest/results-faker.py index b2c47361..d2c6528f 100755 --- a/contest/results-faker.py +++ b/contest/results-faker.py @@ -33,8 +33,12 @@ def combine_infos(config): with open(path, "r") as fp: infos.update(json.load(fp)) - with open(config.get("output", "info"), 'w') as fp: + # atomic write needed + path = config.get("output", "info") + tmp = path + '.new' + with open(tmp, 'w') as fp: json.dump(infos, fp) + os.rename(tmp, path) def main() -> None: