複数の Linux ホストが Network File System(NFS)経由で Codex ホーム(既定は ~/.codex)を共有している場合、同じ SQLite データベースを先行書き込みログ(WAL)モードで同時に開くと、データベースが破損するおそれがあります。CLI や SSH 経由の Codex App で対話型の作業を行う場合は、共有ホームを移行してください。独立したバッチジョブを実行する場合は、各ホストの Codex ホームまたは SQLite ディレクトリを、そのホストのローカルディスクに置いてください。
NFS で SQLite データベースが破損する理由
Codex App とターミナル UI は、SQLite のインデックスを使って会話の一覧を表示します。データベースには、目標やメモリ処理の状態も保存されます。ローカルディスクでは、Codex は通常 WAL モードを使用します。異なるホスト上のプロセス間では、WAL に必要なメモリを共有できません。
Codex は Linux 上で NFS を検出すると、ファイルロックを使うロールバックジャーナルモード(DELETE)でデータベースを作成します。既存の WAL モードのデータベースは、別のホストから開く前に移行してください。
Codex は会話中のイベントを rollout-*.jsonl ファイルにも保存します。各ロールアウトに一度に書き込むプロセスは 1 つだけなので、これらのファイルは移行前から NFS 上に置くことができます。SQLite を移行しても、これらのファイルは元の場所に残ります。
NFS 上の既存ホームの移行
1. 共有ホームの確認
SSH バックエンドを含む各ホストで codex --version を実行してください。codex migrate-nfs-db を含むビルドを使用してください。たとえば、Codex CLI 0.166.0 が該当します。この共有ホームを使用するすべてのホストが、同じ SQLite ディレクトリを使用していることを確認してください。一方のホストがファイルロックを保持している間、もう一方のホストでは競合するロックを取得できないことを、ストレージ管理者に確認してもらってください。マウント先でこの排他制御ができない場合は、SQLite をローカルディスクに置いてください。
移行中は、SQLite ホームやログディレクトリの設定を追加・変更しないでください。
2. すべてのホストでの Codex の停止
進行中のターンを終了し、アプリと CLI を閉じてください。このホームを使用するリモートのアプリサーバー、バックグラウンドデーモン、スケジュール済みジョブも停止してください。移行が完了するまで、すべてのホストでこれらを停止したままにしてください。移行中に別のプロセスが書き込むと、データベースが破損し、目標やメモリへの変更が失われるおそれがあります。
セッションのロールアウトは別のファイルに保存されます。ロールアウトだけでは、データベースの状態をすべて復元することはできません。
デーモンモードでは、CLI はセッションの終了後も動作し続けるバックグラウンドサーバーに接続します。その Unix ソケットを使用できるのは、サーバーを起動したホストだけです。複数のホストが NFS 経由で Codex ホームを共有する場合は、デーモンを使わずに CLI を実行することをお勧めします。デーモンが動作している各ホストで codex app-server daemon stop を実行して停止してください。
CLI が再びデーモンを起動しないようにするには、daemon_auto_start を false に設定してください。この設定は [features] セクションに記述します。共有の config.toml に次のように記述してください。
[features]
daemon_auto_start = false
CLI セッションを 1 回だけデーモンなしで実行するには、--no-daemon を指定してください。このフラグを指定すると、すでに動作中のデーモンにも接続しません。
3. 移行の実行
共有の Codex ホームごとに、Linux ホスト 1 台だけで移行を実行してください。ホームの所有者のアカウントで、普段と同じ設定を使用してください。移行が完了するまで、ほかのホストでは Codex を停止したままにしてください。
codex migrate-nfs-db
4. 会話の再開
コマンドの出力に Skipped logs database と表示された場合は、ログデータベースの場所を確認してください。ローカルディスクにある場合、追加の作業は不要です。NFS 上にある場合は、別のホストで Codex を再び開く前に、ログデータベースのジャーナルモードが DELETE であることを確認するか、ログデータベースをローカルディスクに移してください。
移行に成功したら、別のホストで同じユーザーとして同じプロジェクトを開いてください。アプリで内容を覚えている会話を再開するか、codex --no-daemon resume を実行してください。最後のターンが表示され、会話を続けられることを確認してください。
診断ログのローカルディスクへの移動
この手順は任意ですが、移行後の実施をお勧めします。 診断ログは、エラーや起動に時間がかかる原因を調べる際に役立ちます。ログをローカルディスクに書き込むと、NFS の通信量を減らせます。
各ホストに、ユーザー専用の書き込み可能なログディレクトリを作成してください。log_dir の値には、そのユーザーのログディレクトリの絶対パスを指定します。この設定をユーザーの config.toml に記述してください。たとえば、ユーザー Alice の場合は次のように設定できます。
log_dir = "/var/local/codex/alice/logs"
新しいログは指定したディレクトリに書き込まれます。既存のログは元の場所に残ります。
管理対象の設定で sqlite_home が指定されている場合、log_dir を設定しても、SQLite のログデータベースは管理者が指定したディレクトリに保存されます。詳しくは管理対象の設定を参照してください。
複数のホストへのジャーナルモードの強制適用
まず、対象のホームを使用するすべてのホストで、すべてのクライアントを停止してください。設定名に unsafe が含まれているのは、別のホストが書き込み中のデータベースを変換すると、データベースが破損するおそれがあるためです。
クライアントを停止した状態で、各ホストの管理対象の設定ファイル /etc/codex/requirements.toml に、次の設定を追加してください。
unsafe_enforce_sqlite_journal_mode = true
この設定は、設定済みのホストのすべてのユーザーに適用されます。次にユーザーが Codex を開くと、Codex は NFS 上の既存の WAL データベースを書き込み用に開く際に、自動的に移行します。共有ホームごとに、1 台のホストで移行が完了してから、ほかのホストを再接続してください。移行に失敗した場合は、ほかのクライアントを停止したまま、復旧手順に従ってください。
独立したバッチジョブの実行
無人で実行するジョブで対話型セッションの履歴が不要な場合は、ワーカーのローカルディスク上の Codex ホームを使って codex exec を実行してください。セッションファイルを NFS 上に置く必要がある場合は、CODEX_SQLITE_HOME にジョブごとに専用のローカルディレクトリを指定してください。これにより、複数のワーカーが同じデータベースへのアクセスをめぐって競合するのを防げます。
- 会話の記録を残す場合 各ジョブに、ロールアウトを永続保存するための専用の
CODEX_HOMEと、データベースを置くためのホスト内の専用ディレクトリCODEX_SQLITE_HOMEを用意してください。ワーカーのインデックスは、対話型セッションのインデックスとは別に作成されます。ワーカーの終了後にジョブの内容を確認する必要がある場合は、ロールアウトを$CODEX_HOME/sessions/配下に保存してください。 - 結果だけを残す場合 ジョブのホームをローカルディスクに置き、
codex exec --ephemeralを実行してください。このコマンドは再開可能なセッションを保存しません。-oを使うと最終応答を永続保存用のファイルに書き込めます。--jsonを使うとイベントをジョブランナーにストリーミングできます。
ロールアウトが必要なジョブでは、スケジューラーで両方のディレクトリを作成し、ジョブのホームに認証情報と設定を用意してください。次の例のパスは、このジョブで永続保存に使う Codex ホームと、ワーカーのローカルディスク上の SQLite ディレクトリに置き換えてください。管理対象の設定などで sqlite_home が指定されている場合は、その値が CODEX_SQLITE_HOME より優先されます。
CODEX_HOME="/mnt/nfs/codex/jobs/job-1234" \
CODEX_SQLITE_HOME="/var/local/codex/jobs/job-1234" \
codex exec "このリポジトリのビルド手順を要約してください。"
よくある質問
エラーが NFS に関連しているかどうかを確認するには?
移行時に cannot open source database exclusively などのエラーが表示された場合、Codex はデータベースをロックできませんでした。ローカルディスクでも、別のクライアントが原因で同じエラーが発生することがあります。Linux では、対象のデータベースのパスを指定して findmnt -T "$DB_PATH" を実行してください。nfs または nfs4 と表示されたら、すべてのホストで書き込み中のプロセスがないか調べてください。また、そのマウント先でホスト間のロックが機能することをストレージ管理者に確認してもらってください。まだ動作しているクライアントを停止してから、移行を再試行してください。
移行時の出力では何を確認すればよいですか?
Codex はデータベースごとに、移行した場合は Migrated database: と WAL backup: を、すでに DELETE モードの場合は Already in DELETE mode: を表示します。グループ権限や拡張アクセスルールを使用している場合は、移行後、クライアントを再び開く前にそれらを確認してください。
log_dir がすでに設定されていた場合、コマンドはログデータベースの移行をスキップします。そのデータベースをホスト間で共有する前に、ジャーナルモードが DELETE であることを確認してください。あるいは、ローカルディスクに置いたまま使用してください。
No databases found. と表示された場合は、ホームの所有者のアカウントで実際に使用される SQLite ディレクトリを確認してください。ローカルの一時作業領域が不足している場合は、ホストのローカルディスクで十分な空き容量のあるディレクトリを選び、その絶対パスを --staging-dir で指定してください。
移行に失敗した場合、どうすれば復旧できますか?
ほかのクライアントは停止したままにしてください。エラーメッセージをそのまま記録し、データベースのパスと、出力に表示されたバックアップのパスも控えてください。一部のデータベースはすでに移行済みの可能性があります。元のデータベースと付随するサイドカーファイルは、同じバックアップディレクトリにまとめて保管してください。ロックや空き容量のエラーを解消したら、同じホストで codex migrate-nfs-db を再実行してください。整合性エラーが発生した場合や、置き換え先のデータベースが見つからない場合は、復元に着手する前にコピーを作成し、そのコピーを使って作業してください。セッションのロールアウトは、会話履歴の再構築に役立ちます。目標など、SQLite にのみ保存される状態を復元するには、破損していないデータベースが必要です。
別の CLI セッションを開始する前に、管理対象のストレージ設定によって書き込み先が問題のホームに変更されないことを確認してください。そのうえで、ローカルディスク上の一時ディレクトリを使って Codex を起動してください。新しいホームではサインインが必要になる場合があります。
recovery_home=$(mktemp -d /tmp/codex-nfs-recovery.XXXXXXXX) &&
CODEX_HOME="$recovery_home" CODEX_SQLITE_HOME="$recovery_home" \
codex --no-daemon --sandbox read-only \
"NFS 上の Codex ホームの移行に失敗しました。復旧を手伝ってください。`$ codex doctor` を実行して、破損したデータベースに関する情報を取得してください。各データベースのバックアップは、元のデータベースのパスの末尾に `_wal_migration_backup` を付けた場所にあるはずです。移行に失敗したときに表示されたエラーメッセージをユーザーに尋ねてください。元のファイルには手を加えず、コピーだけを使って復旧する計画を立ててください。"