Skip to content

fix: rotate polling sweep across source directories within per-tick budget - #1130

Open
rootsiemen wants to merge 1 commit into
crazy-goat:masterfrom
rootsiemen:fix-20261031-polling-starve
Open

rootsiemen wants to merge 1 commit into
crazy-goat:masterfrom
rootsiemen:fix-20261031-polling-starve

Conversation

@rootsiemen

Copy link
Copy Markdown
Contributor

Problem

PollingMonitorWatcher restarted every tick at the first source directory. When that directory filled the per-tick budget on its own, it was re-scanned on every tick, and a later directory starved: its parked iterator never got another turn, so a change in the later directory was never detected.

Repro (from the issue)

Source dirs A and B, per-tick budget 2, two matching files in A and a newer matching file in B: after six polling ticks the change in B was never detected, while with B alone it was detected in one tick.

Fix

The sweep now visits source directories in rotated order, starting each tick at the directory the previous tick stopped in (sweepStart), and wraps around. The start resets to the first directory only once every directory has been visited, and resetSweep() (on change detection) also resets it so the next tick starts a fresh sweep from the root of every dir. The per-tick budget is unchanged: every entry still counts, including the first one after a resume. The start is stored as a position into the source-dir list rather than a dir key, because the parent constructor filters out non-existent dirs and the keys may not be sequential. Single-directory behaviour is untouched (rotation over one dir is a no-op).

Tests

  • Added PollingMonitorWatcherTest::testLaterSourceDirIsReachedWhenFirstDirFillsBudget: dirs A (2 files) + B (1 file), budget 2. Tick 1 leaves B parked; the sweep converges (all iterators cleared) within 3 ticks. Verified the test fails on the unfixed code (B stays parked forever) and passes with the fix.
  • tests/PollingMonitorWatcherTest.php: 21 tests, OK (PHP 8.3, PHPUnit 10.5).
  • tests/Reboot/FileMonitorWatcher/FileMonitorWatcherTest.php + tests/PollingMonitorWatcherE2ETest.php: 19 tests, OK (existing single-directory, resume, deletion and budget tests all pass).
  • PHPStan level 8, PHP-CS-Fixer dry-run and Rector dry-run on the changed files: clean.
  • CHANGELOG entry added under [Unreleased] / Fixed.

Note: the full composer test daemon run and bin/lint.sh (needs shellcheck/hadolint) were not run locally; maintainer CI covers them.

Closes #1125

…udget

Each tick restarted at the first source dir, so a first dir that fills
the per-tick budget on its own was re-scanned on every tick and later
dirs starved: their parked iterators never got another turn and
changes there were never detected. The sweep now resumes at the dir
the previous tick stopped in and wraps around, resetting to the first
dir only once every dir has been visited.

Closes crazy-goat#1125
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: polling monitor can starve later source directories

1 participant