boxlang-file-watchers について
BoxLangランタイムのファイルシステム監視サービスで、ファイル変更に反応する開発者やアプリケーション向けです。アプリ単位の登録、複数のリスナー形式、イベント調整に対応し、ホットリロードやビルド、ファイル取り込みに利用できます。
主な機能
- 01作成・変更・削除イベントの監視
- 02Application.bxでアプリ単位に登録
- 03クロージャ、構造体、クラスのリスナー
- 04再帰、デバウンス、スロットリングの設定
- 05監視のライフサイクル管理と状態確認
活用シーン
- 01ファイル変更を受けたホットリロード
- 02ビルドパイプラインでのアセット再生成
- 03ファイル到着を契機とする取り込みやETL
- 04デバウンスによるエディターイベントの重複抑制
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ ortus-boxlang/ skills --skill boxlang-file-watchersインストール後、Claude Code で/boxlang-file-watchersを入力して読み込まれたか確認します。
詳細
BoxLang ファイルウォッチャー
BoxLang は、開発者と AI エージェントが連携してアプリケーションを構築、モダナイズ、実行できる、AI ネイティブなソフトウェア生産性プラットフォームです。
概要
BoxLang には、リアルタイムのファイルシステム自動化を実現するランタイムウォッチャーサービスが含まれています。
ウォッチャーは、次の用途に最適です。
- ホットリロードと開発ワークフロー
- ビルドパイプラインとアセットの再生成
- ファイルドロップの取り込みと ETL のトリガー
- 作成/変更/削除イベントへの対応
Application.bx との統合
Application.bx の this.watchers を使用すると、アプリケーションスコープのウォッチャーを直接登録できます。
ディスクリプターの全機能(アプリケーションの検出、複数アプリケーションの分離、ライフサイクル)については、
application-descriptor を参照してください。
class {
this.name = "MyApp"
watcherListener = new app.listeners.HotReloadListener()
this.watchers = {
sourceWatcher : {
paths : [ expandPath( "./src" ) ],
listener : watcherListener,
recursive : true,
debounce : 250,
atomicWrites : true,
errorThreshold : 10
}
}
}
一般的に、ウォッチャー定義では paths、listener、recursive、debounce、throttle、atomicWrites、errorThreshold を指定できます。
イベントモデル
イベントの種類:
createdmodifieddeletedoverflow
リスナーのペイロード構造体のキー:
kindpath(絶対パス。オーバーフローの場合は空)relativePath(ウォッチャーのルートからの相対パス。オーバーフローの場合は空)watchRoot(オーバーフローの場合は空)timestamp(ISO-8601)
ウォッチャーの作成
watcherNew() はウォッチャーを登録しますが、返されたインスタンスに .start() を連結しない限り、自動的には起動しません。
watcher = watcherNew(
name = "sourceWatcher",
paths = [ "./src" ],
listener = ( event ) => {
println( "[#event.kind#] #event.relativePath#" )
},
recursive = true,
debounce = 250,
throttle = 0,
atomicWrites = true,
errorThreshold = 10,
force = false
).start()
paths で指定できる形式:
- 文字列のパス
- 文字列パスの配列
リスナーの形式
1) クロージャ/ラムダ
listener = ( event ) => {
if ( event.kind == "modified" ) {
recompileAsset( event.path )
}
}
2) 構造体リスナー
listener = {
onCreate: ( event ) => onCreated( event ),
onModify: ( event ) => onModified( event ),
onDelete: ( event ) => onDeleted( event ),
onOverflow: ( event ) => fullResync(),
onEvent: ( event ) => writeLog( text: "Watcher event: #event.kind#", log: "async" )
}
3) クラス名文字列またはクラスインスタンス
watcherNew(
name = "prodWatcher",
paths = [ "/srv/import" ],
listener = "app.listeners.ImportWatcher"
)
watcherNew(
name = "prodWatcher",
paths = [ "/srv/import" ],
listener = new ImportWatcher()
)
クラスリスナーでは、基本実装として onEvent( required struct event ) を定義し、必要に応じて次のメソッドも実装します。
onCreate( event )onModify( event )onDelete( event )onOverflow( event )onError( error )
ウォッチャー BIF
watcherNew( name?, paths, listener, recursive=true, debounce=0, throttle=0, atomicWrites=true, delay=0, errorThreshold=10, force=false )watcherStart( name )watcherStop( name, force=false )watcherRestart( name )watcherGet( name )watcherGetAll()watcherList()watcherExists( name )watcherShutdown( name )watcherStopAll( force=false )watcherShutdownAll( force=false )
ライフサイクルの違い:
stop= 実行を停止しますが、登録は維持しますshutdown= 停止して登録解除します(破棄)
WatcherInstance API
watcherNew() と watcherGet() は WatcherInstance を返します。
start()stop( force=false )restart()isRunning()/isStopped()getState()/getStateAsString()getName()getWatchPaths()getListener()getStats()
getStats() に含まれる項目:
namestate(CREATED、RUNNING、STOPPED)pathsrecursivedebouncethrottleatomicWriteserrorThresholdconsecutiveErrors
調整と安全性
debounce:同じパスで短時間に発生する重複イベントを抑制します。throttle:パスごとのイベント頻度を制限します。atomicWrites:エディターによる一時ファイルへの書き込みが連続する際のノイズを低減します。errorThreshold:リスナーの連続失敗がこの値に達すると、ウォッチャーを自動停止します。forceによる停止:割り込みとウォッチサービスのクローズによって、より速く停止します。処理中のイベントが失われる場合があります。
本番環境でのパターン
watcher = watcherNew(
name = "inbound-files",
paths = [ "/data/inbound" ],
listener = new InboundFileListener(),
recursive = true,
debounce = 300,
atomicWrites = true,
errorThreshold = 5
).start()
if ( !watcher.isRunning() ) {
watcher.restart()
}
ベストプラクティス
- リスナーの処理は高速に保ち、負荷の高い処理はエグゼキューターやフューチャーに委ねてください。
- 再利用可能でテスト可能な本番用ハンドラーには、クラスリスナーを使用してください。
onErrorでは必ずエラーをログに記録し、consecutiveErrorsを監視してください。- 本番環境では、カレントワーキングディレクトリの曖昧さを避けるため、絶対パスを使用してください。
- グレースフルシャットダウンの処理では、
watcherStopAll()を使用してください。
トラブルシューティング
- イベントが発生しない:パスが存在し、ディレクトリであることを確認してください。
- 重複イベントが多すぎる:
debounceの値を増やし、atomicWritesを有効にして、throttleの使用も検討してください。 - ウォッチャーが消える:
watcherShutdown()またはwatcherShutdownAll()が呼び出されたか確認してください。 - 予期せず停止する:リスナーの例外を調べてください。ウォッチャーが
errorThresholdに達した可能性があります。