여러 Linux 호스트가 네트워크 파일 시스템(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 파일에도 저장합니다. 각 롤아웃 파일에는 한 번에 하나의 프로세스만 쓰므로 마이그레이션 전에도 이 파일을 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 세션 하나에만 적용하려면 --no-daemon 플래그를 전달하세요. 이 플래그를 사용하면 이미 실행 중인 데몬도 우회합니다.
3. 마이그레이션 실행하기
공유 Codex 홈마다 Linux 호스트 한 대에서만 마이그레이션을 실행하세요. 홈 소유자의 계정으로 평소와 같은 설정을 사용하세요. 마이그레이션이 끝날 때까지 다른 호스트에서는 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 데이터베이스를 쓰기용으로 열 때 자동으로 마이그레이션합니다. 공유 홈마다 한 호스트에서 마이그레이션이 끝난 뒤에 다른 호스트를 다시 연결하세요. 마이그레이션에 실패하면 다른 클라이언트는 중지한 상태로 두고 복구 절차를 따르세요.
독립적인 배치 작업 실행하기
무인 작업에 대화형 세션 기록이 필요하지 않으면 작업을 실행할 워커의 로컬 디스크에 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 "Summarize this repository's build steps."
자주 묻는 질문
오류가 NFS와 관련이 있는지 어떻게 확인하나요?
cannot open source database exclusively와 같은 마이그레이션 오류는 Codex가 데이터베이스 잠금을 획득하지 못했다는 뜻입니다. 로컬 디스크에서도 다른 클라이언트 때문에 이 오류가 발생할 수 있습니다. Linux에서는 findmnt -T "$DB_PATH"를 실행하세요. 이때 문제가 발생한 데이터베이스의 경로를 사용하세요. 결과에 nfs 또는 nfs4가 표시되면 모든 호스트에서 데이터베이스에 쓰는 프로세스가 있는지 확인하고, 해당 마운트에서 호스트 간 잠금이 작동하는지 스토리지 관리자에게 확인을 요청하세요. 여전히 실행 중인 클라이언트를 모두 중지한 뒤 다시 시도하세요.
마이그레이션 출력에서 무엇을 확인해야 하나요?
Codex는 데이터베이스마다 Migrated database:와 WAL backup:을 출력하거나 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 \
"Help me recover a failed Codex NFS migration, run `$ codex doctor` to get the information about corrupted databases. Backup paths for databases should be in the original database with `_wal_migration_backup` in the end of the file. Ask user for the original error. Plan a recovery using copies and leave the originals untouched."