From 93266dfcadacc4a57536339b76361e81beaff9a4 Mon Sep 17 00:00:00 2001 From: Alexander Stecher <45872305+AlliBalliBaba@users.noreply.github.com> Date: Wed, 19 Mar 2025 13:10:02 +0100 Subject: [PATCH] feat(watcher): log last changed file (#1447) * logs last changed file. * Fixes race condition. --------- Co-authored-by: Alliballibaba --- debugstate.go | 2 +- frankenphp_test.go | 5 +++-- internal/watcher/watch_pattern.go | 2 +- internal/watcher/watch_pattern_test.go | 6 ++++-- internal/watcher/watcher.go | 15 ++++++++------- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/debugstate.go b/debugstate.go index b7ad7f7e..a7941ac7 100644 --- a/debugstate.go +++ b/debugstate.go @@ -37,7 +37,7 @@ func DebugState() FrankenPHPDebugState { func threadDebugState(thread *phpThread) ThreadDebugState { return ThreadDebugState{ Index: thread.threadIndex, - Name: thread.handler.name(), + Name: thread.name(), State: thread.state.name(), IsWaiting: thread.state.isInWaitingState(), IsBusy: !thread.state.isInWaitingState(), diff --git a/frankenphp_test.go b/frankenphp_test.go index 731fa32e..30fc8323 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -672,11 +672,12 @@ func TestFailingWorker(t *testing.T) { } func TestEnv(t *testing.T) { - testEnv(t, &testOptions{nbParallelRequests:1}) + testEnv(t, &testOptions{nbParallelRequests: 1}) } func TestEnvWorker(t *testing.T) { - testEnv(t, &testOptions{nbParallelRequests:1, workerScript: "env/test-env.php"}) + testEnv(t, &testOptions{nbParallelRequests: 1, workerScript: "env/test-env.php"}) } + // testEnv cannot be run in parallel due to https://github.com/golang/go/issues/63567 func testEnv(t *testing.T, opts *testOptions) { assert.NoError(t, os.Setenv("EMPTY", "")) diff --git a/internal/watcher/watch_pattern.go b/internal/watcher/watch_pattern.go index 92507515..12bbe1f8 100644 --- a/internal/watcher/watch_pattern.go +++ b/internal/watcher/watch_pattern.go @@ -13,7 +13,7 @@ import ( type watchPattern struct { dir string patterns []string - trigger chan struct{} + trigger chan string failureCount int } diff --git a/internal/watcher/watch_pattern_test.go b/internal/watcher/watch_pattern_test.go index f01fbe87..748cf4b0 100644 --- a/internal/watcher/watch_pattern_test.go +++ b/internal/watcher/watch_pattern_test.go @@ -149,12 +149,14 @@ func TestInValidExtendedPatterns(t *testing.T) { func TestAnAssociatedEventTriggersTheWatcher(t *testing.T) { watchPattern, err := parseFilePattern("/**/*.php") assert.NoError(t, err) - watchPattern.trigger = make(chan struct{}) + watchPattern.trigger = make(chan string) go handleWatcherEvent(watchPattern, "/path/temorary_file", "/path/file.php", 0, 0) + var path string select { - case <-watchPattern.trigger: + case path = <-watchPattern.trigger: + assert.Equal(t, "/path/file.php", path, "should be associated file path") case <-time.After(2 * time.Second): assert.Fail(t, "associated watchPattern did not trigger after 2s") } diff --git a/internal/watcher/watcher.go b/internal/watcher/watcher.go index 40b65afd..abca9d82 100644 --- a/internal/watcher/watcher.go +++ b/internal/watcher/watcher.go @@ -22,7 +22,7 @@ import ( type watcher struct { sessions []C.uintptr_t callback func() - trigger chan struct{} + trigger chan string stop chan struct{} } @@ -105,7 +105,7 @@ func retryWatching(watchPattern *watchPattern) { } func (w *watcher) startWatching(filePatterns []string) error { - w.trigger = make(chan struct{}) + w.trigger = make(chan string) w.stop = make(chan struct{}) w.sessions = make([]C.uintptr_t, len(filePatterns)) watchPatterns, err := parseFilePatterns(filePatterns) @@ -166,7 +166,7 @@ func handleWatcherEvent(watchPattern *watchPattern, path string, associatedPath } if watchPattern.allowReload(path, eventType, pathType) { - watchPattern.trigger <- struct{}{} + watchPattern.trigger <- path return } @@ -174,29 +174,30 @@ func handleWatcherEvent(watchPattern *watchPattern, path string, associatedPath // so we need to also check the associated path of an event // see https://github.com/dunglas/frankenphp/issues/1375 if associatedPath != "" && watchPattern.allowReload(associatedPath, eventType, pathType) { - watchPattern.trigger <- struct{}{} + watchPattern.trigger <- associatedPath } } -func listenForFileEvents(triggerWatcher chan struct{}, stopWatcher chan struct{}) { +func listenForFileEvents(triggerWatcher chan string, stopWatcher chan struct{}) { timer := time.NewTimer(debounceDuration) timer.Stop() + lastChangedFile := "" defer timer.Stop() for { select { case <-stopWatcher: break - case <-triggerWatcher: + case lastChangedFile = <-triggerWatcher: timer.Reset(debounceDuration) case <-timer.C: timer.Stop() + logger.Info("filesystem change detected", zap.String("file", lastChangedFile)) scheduleReload() } } } func scheduleReload() { - logger.Info("filesystem change detected") reloadWaitGroup.Add(1) activeWatcher.callback() reloadWaitGroup.Done()