mcpField
B
boxlang-file-watchers

boxlang-file-watchers

github.com/ortus-boxlang開発039 回インストール1 週間前に更新
リポジトリ

boxlang-file-watchers について

BoxLangランタイムのファイルシステム監視サービスで、ファイル変更に反応する開発者やアプリケーション向けです。アプリ単位の登録、複数のリスナー形式、イベント調整に対応し、ホットリロードやビルド、ファイル取り込みに利用できます。

主な機能

  1. 01作成・変更・削除イベントの監視
  2. 02Application.bxでアプリ単位に登録
  3. 03クロージャ、構造体、クラスのリスナー
  4. 04再帰、デバウンス、スロットリングの設定
  5. 05監視のライフサイクル管理と状態確認

活用シーン

  1. 01ファイル変更を受けたホットリロード
  2. 02ビルドパイプラインでのアセット再生成
  3. 03ファイル到着を契機とする取り込みやETL
  4. 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 を指定できます。

イベントモデル

イベントの種類:

  • created
  • modified
  • deleted
  • overflow

リスナーのペイロード構造体のキー:

  • kind
  • path(絶対パス。オーバーフローの場合は空)
  • 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() に含まれる項目:

  • name
  • state(CREATED、RUNNING、STOPPED)
  • paths
  • recursive
  • debounce
  • throttle
  • atomicWrites
  • errorThreshold
  • consecutiveErrors

調整と安全性

  • 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 に達した可能性があります。

コメント