4月2日、beadsがv1.0.0をリリースした。目玉機能はembedded Dolt:データベースをインプロセスで実行するゼロコンフィグのバックエンド、管理するサーバーなし。ソロ開発者にとってはbd initだけで完了という約束だった。ポートなし、デーモンなし、設定なし。
Beadboxでのサポート追加をすぐに始めた。ホットフィックス6回、パブリックなロールバック1回、bdのソースコードへのディープダイブを経て、おそらく数ヶ月前に作るべきだったレジリエンスレイヤーを携えて反対側に出てきた。
すべてが壊れる前の朝
その日はクリーンに始まった。コードベース全体でデッドコードハントを実施し、5,350行を削除してコールドローンチを2秒改善したv0.20.0をリリースしていた。42個のbeadsをクローズ。良い朝だった。
そこでbdを0.63.3にアップグレードした。beads v1.0.0のembedded Doltバックエンド上に構築された初のリリースだ。
Beadboxがデータベースを見つけられなかった。Embeddedモードは.beads/dolt/ではなく.beads/embeddeddolt/にデータを保存する。データベース名も変わった。ハードコードされたbeadsから、metadata.jsonから読み取るプロジェクトプレフィックスに。そしてWebSocketサーバーがDOLT_HASHOF_TABLE経由でO(1)の変更検知に使っていたbd sqlは、embeddedモードではまったくサポートされていない。
最初の10分で3つの前提が崩れた。
1日で6リリース
発見、修正、リリース、再発見。
v0.20.1はOSキーチェーンを使った認証情報の永続化を追加し(すでに進行中だった6個のbeads分の作業)、カスタムステータスフィルターのバグを修正し、Windows固有の問題をパッチした。
v0.20.2はBeadboxにmetadata.jsonからdolt_databaseを読み取ることを教え、リネームされたデータベースを見つけられるようにした。
v0.20.3はembeddedモードのガードを追加した。すべてのbd sql呼び出しにチェックをラップした:embeddedモードなら、直接SQLクエリの代わりにCLIベースのポーリングにフォールバックする。getDoltDir関数は最初にembeddeddolt/を見ることを学んだ。
v0.20.4はembeddedレイアウト用の--dbパス正規化を修正した。古いディレクトリ構造で動いていたパスが新しい構造では壊れた。
各修正が次の問題を明らかにした。
Flock
v0.20.4の後、安定したと思った。そこでシンプルな同時実行テストを実行した:5つのbd list呼び出しを同時に。
4つが失敗した。
Embedded Doltはコマンドの全ライフタイムにわたってデータベースの排他的ファイルロック(flock)を取得する。PersistentPreRunからPersistentPostRunまで、他の何もアクセスできない。これは設計通り。これがないと、並行エンジン初期化がnil-pointer panicを引き起こす(beads#2571)。Flockはクラッシュを防ぐ。しかし、embeddedモードではbdが事実上シングルプロセスであることも意味する。
Beadboxはシングルプロセスではない。WebSocketサーバーは毎秒変更をポーリングする。UIはページロード時に複数のserver actionを発火する。バックグラウンドポーラーが動いている間にアプリを操作するユーザーは、並行したbd呼び出しを生成する。Flockは最初の1つを除いてすべてをブロックする。
DoltHubのブログ記事はembedded実装の想定動作を記述していた:並行呼び出し元は「指数バックオフで自然にキューイングされる」はず。しかしarchがリリースされたソースコードをレビューし、bdがTryLockをLOCK_NB(ノンブロッキング)で使用していることを発見した。待たない。即座に失敗する。ロックレイヤーは2つ:上のbdのflock、その下のDoltのドライバーレベルバックオフ。第1レイヤーが第2レイヤーをショートサーキットする。リトライロジックはコードベースに存在するが、flockがDoltのバックオフが実行される前に接続を拒否するため、実行されることはない。
修正(FlockSharedNonBlockによるリード操作用共有ロック)はbdのソースに存在する。まだ接続されていないだけだ。
Beadbox はこの問題を解決します。
エージェントフリート全体が今何をしているか、リアルタイムで把握できます。
ベータ期間中は無料でお試し →
ロールバックした
動き続けるターゲットに対してホットフィックスをリリースし続けるか、引き下がって適切なレジリエンスレイヤーを構築するか。引き下がった。
v0.20.xリリースはすべてパブリックリポジトリから削除された。v0.19.0が推奨バージョンとして復帰した。何が起きたか、何をすべきかを説明するディスカッションを投稿し、beadbox.appにバナーを追加した。決定から完了まで30分。
壊れたリリースが公開されている1時間ごとに、誰かがダウンロードし、flockの問題に遭遇し、プロダクトのせいにする。ロールバックを説明する方が、他人の悪い初回体験をデバッグするよりましだ。
自分たちだけではなかった
デバッグ中に、beadsユーザーのKevinがbeads#2938を投稿した:"Beads feels painful to use." 彼は9.5時間をかけて、まさに自分たちが直面していたembedded-to-serverの混乱を含む問題をデバッグしていた。v1.0.0へのアップグレードが彼のワークスペースをサーバーモードからembeddedモードに静かに切り替え(beads#2949)、既存のissueを空の新しいデータベースの後ろに隠してしまった。
9.5時間。経験豊富なユーザーであって、新規ユーザーではない。beadsをよく知る人の体験がこれなら、問題はユーザーにはない。マイグレーションパスにある。
v0.21.0で構築したもの
個別の障害にパッチを当てる代わりに、ロック競合を通常の動作条件として扱うレイヤーを構築した。
指数バックオフ付きflockリトライ。 bd CLIの各呼び出しは最大5回リトライする。試行間隔は100msから1.6秒。lib/bd.tsの1箇所に置かれているため、すべてのコマンドが無料で得られる。一般的なケースをカバーする:2つの呼び出しが衝突し、1つが少し待ち、両方成功する。
グレースフルデグラデーションUI。 ロック競合でエラー画面にならなくなった。アプリはリフレッシュインジケーター付きで古いデータを表示する。競合が30秒以上続くと、琥珀色のバナーが状況を説明する。ロックが解除されるとバナーが消え、データが自動的にリフレッシュされる。
オートプロモート提案。 繰り返しの競合がサーバーモードへの移行を提案するトリガーになる:バックアップ、--serverで再初期化、リストア。ワンクリック。Beadboxを他のbd利用者と並行して実行する人にとって正しい答えであり、今やアプリがそれを教えてくれる。
Embeddedモード検出。 getDoltDirはembeddeddolt/をチェックし、適切にルーティングする。bd sql呼び出しはガードされている。WebSocketパイプラインはembeddedモードでCLIベースのポーリングにフォールバックする(遅いが、シングルプロセス制約を尊重する)。
学んだこと
Embedded Doltは設計上シングルプロセス。 バグではない。Flockは本当のpanicを防ぐ。beadsワークスペースを並行して利用するツールは、アクセスをシリアライズするかサーバーモードで実行する必要がある。Beadboxにとって、サーバーモードが正しいデフォルト。Embeddedはリトライレイヤーが時折の衝突を吸収する軽い使用なら動く。
ドキュメントは意図を記述していた。実装ではなく。 DoltHubブログはバックオフと言った。コードはTryLockとLOCK_NBと言った。ドキュメントがそう言っているから並行リードが動くはずだと仮定して時間を費やした。ソースを読むことで混乱は数分で解消した。動作がドキュメントと一致しないなら、コードを読め。
リリース前に同時実行をテストせよ。 v0.20.4が公開されるまで、並行bd呼び出しを実行しなかった。for i in {1..5}; do bd list & done; waitで、どのリリースよりも前にflockの問題を検出できていた。5秒のテストでロールバックを回避できたはずだ。
早めにロールバックせよ。 前に進み続ける本能は強い。近づいている、修正が見える、もう1回リリース。しかし、公開されたままの壊れたリリースは簡単に取り消せない信頼の引き出しだ。v0.19.0に戻ることで、パニック的な小刻みリリースではなく、レジリエンスレイヤーを適切に構築する余裕ができた。
環境変数を確認せよ。 BEADS_DIRがbdを間違ったワークスペースに向けていたために何時間も無駄にした。bdはBeadboxが監視しているものとは別のデータベースを発見し、症状はデータ破損のように見えた。bdコマンドが予期しない結果を返すなら、何よりも先にenv | grep BEADSを。
現在の状況
v0.21.0がbeads v1.0.0サポート、レジリエンスレイヤー、OSキーチェーン経由の認証情報永続化とともにリリースされた。リリースディスカッションに完全な詳細がある。
beads v1.0.0のembeddedモードで断続的な障害が発生しているなら、v0.21.0のリトライレイヤーで対処できるはず。Beadboxを同じワークスペースにアクセスする他のツールと並行して実行しているなら、サーバーモードに切り替えよう。オートプロモートフローならワンクリックだ。
そしてSteveやbeadsチームの方がこれを読んでいるなら:リード用の共有flockがルートコーズをアップストリームで修正できる。beads#2939(Unix domain sockets)はローカル接続もよりクリーンにする。何がリリースされようと、その周りで構築を続ける。
自分で試してみる
まず beads を連携レイヤーとして導入。ビジュアルな管理が必要になったら Beadbox を追加。
ベータ期間中は無料。アカウント不要。Doltにネイティブ対応。