Skip to content

Commit 896e057

Browse files
committed
fix: restore trailing debounce in EventWatcher
The rewritten debounce fired a fixed 50ms after the first change rather than after changes stopped arriving, turning it into a throttle. A sustained burst of appends therefore produced one callback per 50ms window instead of one per quiet period, which is what TestEventWatcher_DebounceCollapses caught under the race detector. Reset the window on every new change, as the original per-session timers did, and cap the total deferral at 500ms so a continuously active session still refreshes instead of having its window extended forever. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: dac50159-d2c8-4ade-920a-333a51fc9ce3
1 parent deebcef commit 896e057

1 file changed

Lines changed: 34 additions & 7 deletions

File tree

‎internal/data/eventwatcher.go‎

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,16 @@ import (
1212
"github.com/jongio/dispatch/internal/validate"
1313
)
1414

15-
// eventWatcherDebounce is the minimum interval between re-classifications
16-
// of the same session after a file change. Rapid writes (e.g. multiple
17-
// events.jsonl appends in quick succession) are collapsed into one callback.
15+
// eventWatcherDebounce is how long the watcher waits for changes to stop
16+
// arriving before re-classifying. Rapid writes (e.g. multiple events.jsonl
17+
// appends in quick succession) are collapsed into one callback.
1818
const eventWatcherDebounce = 50 * time.Millisecond
1919

20+
// eventWatcherMaxDelay caps how long classification can be deferred while
21+
// changes keep arriving. Without it, a continuously active session would
22+
// reset the debounce window forever and never refresh in the UI.
23+
const eventWatcherMaxDelay = 500 * time.Millisecond
24+
2025
// EventWatcher monitors the Copilot CLI session-state directory for changes
2126
// using OS-level file system notifications (fsnotify). When events.jsonl or
2227
// lock files change, it re-classifies just the affected session and fires
@@ -265,11 +270,33 @@ func (ew *EventWatcher) debounceLoop(stateDir string) {
265270
case <-ew.wake:
266271
}
267272

273+
// Trailing debounce: keep extending the window while changes are
274+
// still arriving, but never past eventWatcherMaxDelay.
275+
deadline := time.Now().Add(eventWatcherMaxDelay)
268276
timer.Reset(eventWatcherDebounce)
269-
select {
270-
case <-ew.stop:
271-
return
272-
case <-timer.C:
277+
278+
settle:
279+
for {
280+
select {
281+
case <-ew.stop:
282+
return
283+
284+
case <-ew.wake:
285+
if !timer.Stop() {
286+
<-timer.C
287+
}
288+
wait := eventWatcherDebounce
289+
if remaining := time.Until(deadline); remaining < wait {
290+
wait = remaining
291+
}
292+
if wait <= 0 {
293+
break settle
294+
}
295+
timer.Reset(wait)
296+
297+
case <-timer.C:
298+
break settle
299+
}
273300
}
274301

275302
ew.mu.Lock()

0 commit comments

Comments
 (0)