この記事について
この記事は、生成AIを活用した自動生成フローで作成しています。Microsoft LearnのFileSystemWatcher公式資料を確認し、1回の保存で複数イベントが発生するケースを前提に、短時間の重複通知をまとめるdebounceの考え方をPowerShellで試せる形に整理しています。検証ステータス:📘 公式仕様確認済み・実機未確認
FileSystemWatcherを実務で使うと、「ファイルを1回保存しただけなのにChangedが2回、3回と来る」ことがあります。
これは異常ではなく、アプリが保存時に複数のI/Oを行うことがあるためです。
そこで必要になるのが、短時間に同じ対象へ来たイベントを1回の処理へまとめる debounce です。
まず重複イベントを観察する
$dir = Join-Path $env:TEMP 'papanda-watch-debounce'
New-Item -ItemType Directory -Force $dir | Out-Null
$watcher = [System.IO.FileSystemWatcher]::new($dir)
$watcher.NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite, Size'
$watcher.EnableRaisingEvents = $true
Register-ObjectEvent -InputObject $watcher -EventName Changed -SourceIdentifier 'PapandaChanged' | Out-Null
$file = Join-Path $dir 'demo.txt'
'first' | Set-Content $file
'second' | Add-Content $file
'third' | Add-Content $file
Start-Sleep -Seconds 1
Get-Event -SourceIdentifier 'PapandaChanged' |
Select-Object TimeGenerated,
@{n='Name';e={$_.SourceEventArgs.Name}}
環境によってイベント数は変わります。重要なのは、書込み回数とイベント数が1対1とは限らないことです。
debounceとは何か
たとえば同じ demo.txt に500ms以内で複数イベントが来たら、最後の1件だけを「処理対象」とみなす考え方です。
flowchart LR A[Changed #1] --> W[500ms待つ] B[Changed #2] --> W C[Changed #3] --> W W --> P[demo.txt を1回だけ処理]
イベントそのものを消すのではなく、後続処理を何回実行するかを制御するのがポイントです。
まずはバッチで重複をまとめてみる
イベントを1秒ためてから、ファイル名単位にまとめます。
$events = Get-Event -SourceIdentifier 'PapandaChanged'
$events |
Group-Object { $_.SourceEventArgs.FullPath } |
ForEach-Object {
$latest = $_.Group |
Sort-Object TimeGenerated -Descending |
Select-Object -First 1
[pscustomobject]@{
Path = $_.Name
EventCount = $_.Count
UseEvent = $latest.TimeGenerated
}
}
たとえば EventCount = 3 でも、後続処理は1回だけにできます。
これはリアルタイムdebounceの最小概念版です。本番ではTimerやキューを使い、「最後のイベントから一定時間静かになったら処理する」形へ育てます。
なぜ単純にChangedの中で処理しないのか
たとえば受信CSVをChangedイベントごとにDBへ登録すると、同じファイルを複数回取り込む危険があります。
さらにイベント発生時点では、相手アプリがまだファイルを書込み中かもしれません。
そのため実務では、
イベントを受け取る
同一ファイルの短時間イベントをまとめる
ファイルサイズや更新時刻が安定したか確認する
1回だけ処理する
処理済み状態を記録する
という段階を分ける方が安全です。
debounceだけでも足りない
FileSystemWatcherは大量変更時に内部バッファがあふれ、イベントを取りこぼす可能性もあります。
つまり、
重複イベント → debounce
取りこぼし → 定期再走査
二重処理 → 冪等化、処理済み管理
と別々の対策が必要です。
仕事で使うなら
共有フォルダへ届くCSVの自動取込
スキャナPDFの後処理
外部システムから届くファイル連携
ログファイル更新監視
ビルド成果物の自動処理
では、FileSystemWatcherを「通知装置」として使い、処理の正しさは別の状態管理で保証する設計が向いています。
後始末
Get-Event -SourceIdentifier 'PapandaChanged' |
Remove-Event -ErrorAction SilentlyContinue
Unregister-Event -SourceIdentifier 'PapandaChanged' -ErrorAction SilentlyContinue
$watcher.Dispose()
Remove-Item $dir -Recurse -Force
まとめ
FileSystemWatcherは1操作で複数イベントを出すことがある
debounceは短時間の同一対象イベントを1回の処理へまとめる考え方
イベントAction内で即本処理するより、キューや状態管理を挟む
取りこぼし対策と重複対策は別
実務では冪等化・再走査・処理済み管理も組み合わせる
