【ITニュース解説】Observability that cannot break a run
2026年10月10日に「Dev.to」が公開したITニュース「Observability that cannot break a run」について初心者にもわかりやすく解説しています。
ITニュース概要
ビルドツール`vx`は監視機能で、情報送信エラーでもビルド停止なし。情報収集はビルドと独立し、エラー時も続行。不要時はコストゼロ。リモートキャッシュも同様に障害に強い。
ITニュース解説
システム開発では、作成したプログラムが意図した通りに動作するか、どこに問題があるかなどを監視し、システムの内部状態を外から把握できるようにする仕組みが重要になる。これを「Observability(可観測性)」と呼ぶ。例えば、エラーの発生状況、処理にかかる時間、システムの負荷といった情報がこれに当たる。もし問題が発生しても、これらの情報があれば原因を素早く特定し、解決に役立てることができる。
通常、ソフトウェアを開発する際には、ソースコードを実際に動作するプログラムに変換する「ビルド」という作業を行う。このビルドツールには、ビルドの進行状況や結果、発生したエラーなどをSentryのようなエラー報告サービス、Slackのようなチャットツール、あるいは各種メトリクス収集ツールなどに通知するための連携機能が組み込まれていることが多い。しかし、これらの外部サービスとの連携は、ネットワークの不調やサービス側の問題によって、情報送信がうまくいかなくなることがある。その結果、本来ならばビルド作業そのものとは直接関係のない「情報の送信」という付随的な処理が失敗したために、ビルド作業全体が中断されてしまうという問題が頻繁に発生していた。このような状況を防ぐためには、開発者が「エラーが発生してもビルドを止めないように」と注意深くコードを記述するといった運用上のルールで対応することが一般的だった。
しかし、vxというビルドツールは、この問題を解決するために、可観測性の仕組みを「構造」として組み込むという新しいアプローチを取っている。つまり、開発者の注意や運用ルールに頼るのではなく、システムそのものの設計によって、可観測性の機能がビルド作業を中断させないことを保証するのだ。
この保証を実現するために、vxでは「TelemetrySink(テレメトリーシンク)」という特別なインターフェース(契約)が定義されている。TelemetrySinkは、ビルド中に発生する様々なイベントを収集し、外部に送信するための処理を行う部分だ。このインターフェースには、主に三つのメソッドがある。onRecordメソッドは、タスクの開始や終了、ログの出力といったビルド中の個々のイベントデータを逐次受け取る。このメソッドは、呼び出されたらすぐに処理を終えて戻る必要があり、時間のかかる外部へのデータ送信は行わない。代わりに、受け取ったデータを一時的にメモリに溜めておく(バッファリングする)役割を担う。onRunSummaryメソッドは、ビルド全体の最終的なサマリー情報を受け取る。そして、flushメソッドが、ビルドがすべて完了した最後に一度だけ呼び出される。このflushメソッドで、onRecordでバッファリングしておいたデータをまとめて外部サービスに送信する。もし送信処理に時間がかかったり、ネットワークが不安定で遅延が発生したりしても、デフォルトで3秒というタイムアウトが設定されており、それを超えると処理が中断される。これにより、外部サービスとの通信に問題があっても、ビルドプロセス全体が無限に待たされることなく、必ず終了することが保証される。
TelemetrySinkの設計において最も重要なのは、それがビルドの実行に一切影響を与えられないという点だ。TelemetrySinkに渡される情報には、ワークスペースのルートパスやキャッシュディレクトリといった「読み取り専用」のコンテキスト情報と、イベントの「プレーンなデータ」のみが含まれる。つまり、ビルドのスケジュール管理、キャッシュの操作、実際のタスク実行といったビルドの中核的な機能に直接アクセスする手段は一切提供されない。これは、開発者が「ビルドをブロックしないでください」というルールを守ることを求めるだけでなく、そもそもTelemetrySinkがビルドプロセスに干渉するための「道筋」自体が存在しないように設計されているためだ。この構造的な制約により、TelemetrySinkは、いかなる場合でもビルドの挙動を変えたり、中断させたりすることができない。
さらに、TelemetrySinkの実装に何らかの不具合があり、onRecord、onRunSummary、flushのいずれかのメソッドでエラーが発生したとしても、その特定のTelemetrySinkはその後のビルド実行中は無効化され、警告が一度表示されるだけで済む。他のTelemetrySinkは引き続き正常に動作し、最も重要なビルド全体の成功や失敗には全く影響を与えない。これは、可観測性の仕組み自体がビルドの安定性を損なわないための重要な安全策である。また、特定の種類のイベント、例えばtask.logのように大量に発生する可能性のあるログデータは、TelemetrySinkが明示的に「この種類のデータが欲しい」と指定しない限り、イベントソースから送られてこない。これにより、不要なデータの処理や送信コストを削減できる。
一方で、TelemetrySinkとは異なり、ビルドの根幹をなすようなプラグイン、例えばビルド設定を読み込むプラグインや、実際にタスクを実行する「エグゼキューター」、あるいはキャッシュの生成に関わる「キャッシュファクトリー」といった部分は、全く異なる設計思想に基づいている。もしこれらの「負荷を支える」重要なプラグインのセットアップ中にエラーが発生した場合は、ビルドが開始される前に、エラーを発生させたプラグインの名前と共にビルド全体を中断させる。これは、ビルドの安定性や正確性に直接関わる部分で問題が発生した場合、静かに失敗するよりも、早期に、そして明確にエラーを報告することで、開発者に速やかな修正を促すためだ。
vxの設計には、安全性と同じくらい重要なもう一つの特性がある。それは、もしTelemetryの機能、つまりTelemetrySinkが全く使われていない場合、そのためのコストが一切発生しないということだ。例えば、イベントをやり取りするための内部バスが登録されたり、ビルドの要約情報が組み立てられたり、あるいはソースコードの履歴(Git)が調べられたりといった処理は、TelemetrySinkが一つも存在しない環境では、全く行われない。これはvxのあらゆる部分における一般的な設計原則であり、「何も設定されていなければ、何も呼び出されない」という考え方に基づいている。
このTelemetrySinkの仕組みの上に、いくつかの実用的なツールが構築されている。一つは@vzn/vx-otelというプラグインで、ビルドの実行状況をOpenTelemetryという標準的な形式のトレース、メトリクス、ログとしてHTTP/JSON経由で送信する。このプラグインはOpenTelemetryの複雑なSDKに依存せず、軽量に実装されている。各タスクの実行状況はタスクが終了するたびに個別に送信されるため、CI/CD環境でビルドが実行されている最中でも、その状況をダッシュボードでリアルタイムに追跡できる。データの送信処理がタスクの実行を待たせることはない。もう一つは@vzn/vx-ciというプラグインで、ビルドの実行結果をGitHub Actionsのジョブサマリーとして書き込んだり、GitHubのトークンが提供されていれば、コミットに対するチェック実行の結果として詳細を報告したりする。これにより、プルリクエストのチェックリストでビルドの失敗理由がすぐにわかるようになる。これらのプラグインの他にも、onRecordでデータをバッファリングし、flushで外部にポストするというシンプルなロジックで、数ダースのコード行で独自のTelemetrySinkを簡単に作成できる。
「絶対に失敗させない」というこの設計思想は、TelemetrySinksに限らず、リモートキャッシュの機能にも適用されている。リモートキャッシュとは、ビルドの成果物などをネットワーク経由で共有し、再利用することでビルド時間を短縮する仕組みだ。もしリモートキャッシュへのアクセスでエラーが発生したり、タイムアウトしたり、あるいはネットワークが届かなくなったりしたとしても、vxのビルドは中断されない。その場合、リモートキャッシュからの取得は失敗とみなされ、ローカルのキャッシュを探すなど、次の手段に処理が移り、ビルドは最後まで完了する。リモートでの問題は、ビルドの速度が遅くなる原因にはなるが、ビルド自体を壊すことはない。そして、問題が発生したことは警告として通知されるため、ユーザーは状況を把握できる。
vxはJavaScriptのモノレポ(複数のプロジェクトを一つのリポジトリで管理する方式)向けのタスクランナーおよびビルドキャッシュツールであり、この「壊れない可観測性」という設計哲学により、ビルドプロセスの安定性を高めている。