자동화 slecs

백업 로그인 중 cron 동시 실행 방지

목차

백업 로그인 기능을 추가하면서 동시성 제어의 중요성을 다시 한 번 깨달았다. 계정 관리 스크립트가 자동화되면서 여러 작업이 병렬로 실행될 가능성이 높아졌고, 특히 사용자가 수동으로 백업 로그인을 수행 중일 때 cron이 동시에 계정 상태를 변경하려 하면 상태 불일치나 데이터 손상이 발생할 수 있다는 걸 깨달았다.

문제: 백업 로그인 중 cron 충돌

scripts/claude-account.py는 정기적으로 계정 상태를 점검하고 필요한 작업을 수행하는 자동화 스크립트다. 그런데 백업 로그인 기능이 추가되면서 새로운 시나리오가 생겼다:

  • 사용자가 수동으로 백업 로그인을 진행 중일 때 → 계정 시크릿 변경, 세션 갱신, 인증 상태 업데이트 등
  • 동시에 cron 작업이 정기 실행되면 → 로그인 중인 계정에 대해 일괄 업데이트, 상태 초기화, 오래된 세션 정리 등을 시도
  • 결과 → Race condition으로 일부 변경이 손실되거나, 계정이 의도치 않게 LOCKED되거나, 백업 로그인이 중도에 실패하는 현상

실제 운영 환경에서 이런 문제는 "왜 가끔 로그인이 실패해?" 같은 불명확한 버그 리포트로 나타나곤 한다. 재현도 어렵고, 타이밍에 민감해서 테스트로 잡기도 힘들다.

해결: lock/unlock 메커니즘

이번 작업에서는 파일 기반 또는 상태 기반 lock을 도입했다. 백업 로그인이 시작되면 계정을 LOCKED 상태로 표시하고, cron이 실행될 때는 lock 상태를 확인해서 LOCKED 된 계정은 건드리지 않도록 했다.

단계 동작 목적
1. 백업 로그인 시작 계정 lock cron 진입 방지
2. 백업 로그인 중 lock 유지 상태 격리
3. 백업 로그인 완료 unlock 정상 운영 복구
4. cron 실행 전 lock 상태 체크 LOCKED 계정 제외

이 패턴은 단순하지만 효과적이다. 백업 로그인 로직에서는 lock을 획득하고 해제하는 책임만 지면 되고, cron은 단순히 "이 계정 지금 locked니?" 하고 묻기만 하면 된다.

# 의사코드 (실제 구현은 파일시스템/DB lock일 수 있음)
def backup_login(account_id):
    try:
        lock_account(account_id)  # lock 획득
        # 실제 로그인 처리: 시크릿 생성, 세션 갱신 등
        perform_login_operations(account_id)
    finally:
        unlock_account(account_id)  # 항상 해제

def cron_task():
    for account in get_all_accounts():
        if is_locked(account.id):
            continue  # LOCKED 계정은 건너뛰기
        # 정기 유지보수 작업
        maintain_account(account)

자동화 스크립트에서의 동시성 제어

이 패턴은 특히 오래된 cron 기반 자동화에서 자주 놓치는 부분이다. 초기에 스크립트를 만들 때는 "내가 수동으로 실행하거나 정해진 시간에만 cron이 실행되겠지"라고 생각해서 동시성을 고려하지 않는다. 그런데 나중에 더 많은 기능이 추가되거나 운영 요구사항이 바뀌면서 사용자 수동 작업과 자동 작업이 섞여 실행되는 상황이 생긴다.

이렇게 될 때 선택지는 몇 가지다:

  1. Lock 도입 (이번 방식) — 간단하고 명확하지만, 백업 로그인이 오래 걸리면 cron이 그만큼 뒤밀린다.
  2. 큐 기반 아키텍처 — 모든 작업을 큐에 넣고 순차 처리. 복잡하지만 순서 보장.
  3. 격리 (Isolation) — 백업 로그인은 별도 프로세스/트랜잭션에서 처리. 중간 정도 난이도.

이번에는 백업 로그인 기능이 이미 추가되었고, cron은 기존 로직이라서 최소 침투적인 lock 방식을 골랐다. 나중에 스케일링이 필요하면 다시 검토할 가능성도 있다.

배운 점

  • 자동화 스크립트도 동시성을 고려해야 한다. 초기에는 순차 실행만 생각하기 쉽지만, 시간이 지나면서 예상치 못한 동시 접근이 항상 생긴다.
  • 상태 격리는 단순한 게 좋다. 복잡한 트랜잭션 로직보다 "이건 지금 작업 중" 같은 한눈에 알 수 있는 플래그가 디버깅도 쉽고 유지보수도 편하다.
  • 테스트하기 어려운 버그는 애초에 구조에서 방지하는 게 낫다. Race condition을 테스트 코드로 100% 커버하기는 어렵지만, lock 메커니즘을 있으면 그 자체가 문제 예방이다.

🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.