1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
"""
pending_lock.py — shared lockfile helper for pending-review.jsonl writers.
All scripts that read-modify-write (or append to) pending-review.jsonl must use
locked_write() so they don't corrupt each other's changes. The same convention
is used by:
- fetch_all_sources.py (imports from here)
- check_feed_updates.py (imports from here)
- mark_reviewed.py (imports from here)
- review_loop.sh (acquires path + ".lock" directly via shell)
Lock protocol:
- Lock file: path + ".lock"
- Lock file contains the owning PID as a plain integer string.
- If the PID is dead (os.kill raises OSError), the lock is stolen.
- File is written atomically via a temp file + os.replace().
"""
"""Read-modify-write *path* under an exclusive advisory lockfile.
Uses ``path + ".lock"`` as the lock. The lockfile contains the writer's
PID so stale locks from crashed processes are detected and stolen.
*transform_fn* receives the current file content (empty string if the file
does not exist) and returns the new content to write. The write is
performed atomically via a temp file + :func:`os.replace`.
"""
= +
# Acquire lock — spin with 0.1 s sleep until we own it or steal a dead one.
=
break # we own the lock
=
=
# raises OSError if process doesn't exist
# process alive — wait
# Dead PID or unreadable lockfile — steal it.
pass
=
=
=
= +
pass