PowerShellでFileSystemWatcherの重複イベントをまとめる ― debounceを試す

PowerShellカテゴリを表すパンダのイラスト PowerShell

この記事について
この記事は、生成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. イベントを受け取る

  2. 同一ファイルの短時間イベントをまとめる

  3. ファイルサイズや更新時刻が安定したか確認する

  4. 1回だけ処理する

  5. 処理済み状態を記録する

という段階を分ける方が安全です。

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内で即本処理するより、キューや状態管理を挟む

  • 取りこぼし対策と重複対策は別

  • 実務では冪等化・再走査・処理済み管理も組み合わせる

公式情報・一次情報

文書情報

記事タイトル
PowerShellでFileSystemWatcherの重複イベントをまとめる ― debounceを試す
作成日
更新日
Source URL
https://papanda925.com/?p=15376

ライセンス: 本記事のうち、当サイトが権利を有する本文・自作図表は、特記なき限り CC BY 4.0 で利用できます。生成AIを活用して作成・編集した内容を含みます。コードについて、別途ライセンス表示またはリンク先GitHubリポジトリのライセンスがある場合は、その条件を優先します。引用・第三者資料・画像・商標等は本ライセンスの対象外です。 利用ポリシー

タイトルとURLをコピーしました