Commit 972f8d5
Self-heal indexing so a stalled watcher can't silently stop it (#12)
* Self-heal indexing so a stalled watcher can't silently stop it
New screenshots are indexed only via the live FSEvents->OCR pipeline, and
rescanAll() fires solely from the manual Rescan Now button. When that live
path stalls - a long-lived FSEvent stream on an iCloud Drive folder quietly
stops delivering, or one file hangs OCR forever - indexing dies until the
app is relaunched. It stayed dead for 8 days in the wild.
Two complementary fixes:
- OCR can no longer hang. recognize(at:) now wraps the decode and Vision
call in a withTimeout watchdog (60s default) that throws OCRError.timedOut,
so a single bad file can't wedge the drain queue on an await that never
resumes.
- The indexer runs a maintenance tick every 5 minutes that re-arms the
FSEvents stream and rescans. It runs independently of the drain queue, so
even a wedged queue recovers, and a dead watcher gets a fresh stream.
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: GitButler <gitbutler@gitbutler.com>
* Address PR review: make the OCR watchdog actually free the caller
The first cut of withTimeout raced the work against a sleeper inside a
withThrowingTaskGroup. A structured group can't return from its scope until
every child finishes, so when the OCR work hangs in a non-cancellable
Vision/ImageIO call the group hangs with it - the watchdog never fires and
the indexer can still wedge on the exact bad-file case it was meant to fix.
Codex and Copilot both flagged this.
Rework withTimeout to run the work in an unstructured task the caller never
awaits directly, suspending instead on a continuation that whichever of
{work, deadline} settles first resumes via a one-shot gate. A hung work task
is orphaned rather than awaited, so the caller is always freed at the
deadline. Added a regression test with a Thread.sleep operation that ignores
cooperative cancellation.
Also from review:
- Guard periodicMaintenance with isMaintenanceRunning so a scan that outruns
the 5-minute interval can't stack a second concurrent scan.
- guard let self in the maintenance loop so the task exits if the actor is
deallocated instead of looping forever.
- Fix a comment typo (worked -> worker task).
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: GitButler <gitbutler@gitbutler.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: GitButler <gitbutler@gitbutler.com>1 parent c852a35 commit 972f8d5
3 files changed
Lines changed: 186 additions & 10 deletions
File tree
- Sources/VistaCore
- Tests/VistaCoreTests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
53 | 69 | | |
54 | 70 | | |
55 | 71 | | |
| |||
98 | 114 | | |
99 | 115 | | |
100 | 116 | | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
101 | 128 | | |
102 | 129 | | |
103 | 130 | | |
104 | 131 | | |
105 | 132 | | |
106 | 133 | | |
| 134 | + | |
107 | 135 | | |
108 | 136 | | |
109 | 137 | | |
110 | 138 | | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
111 | 154 | | |
112 | 155 | | |
113 | 156 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
37 | 47 | | |
38 | 48 | | |
39 | 49 | | |
40 | 50 | | |
41 | | - | |
42 | | - | |
43 | | - | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
44 | 55 | | |
45 | 56 | | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
50 | | - | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
51 | 68 | | |
52 | | - | |
53 | | - | |
54 | 69 | | |
55 | 70 | | |
56 | 71 | | |
| |||
136 | 151 | | |
137 | 152 | | |
138 | 153 | | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
139 | 214 | | |
140 | 215 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 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 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
33 | 91 | | |
34 | 92 | | |
35 | 93 | | |
| |||
0 commit comments