IT

Python 스케줄러 중복 실행 방지: 안정적인 배치 운영을 위한 락 파일(Lock File) 설계 가이드

AI 자동화 실무 2026. 7. 18. 11:20
SMALL

파이썬 스케줄러에서 락 파일(Lock File)은 특정 작업이 이미 실행 중일 때 동일한 작업이 중복으로 돌아가지 않도록 막는 가장 확실한 장치입니다. 단순히 파일의 존재 여부만 확인하는 수준을 넘어, 비정상 종료 시에도 시스템이 멈추지 않게 설계하는 것이 핵심입니다.

데이터 엔지니어링이나 백엔드 운영을 하다 보면 크론탭(Crontab)이나 간단한 스케줄러가 예상보다 오래 걸려 다음 실행 주기와 겹치는 상황을 자주 마주합니다. 이때 적절한 제어 장치가 없다면 동일한 데이터를 두 번 처리하거나, DB 커넥션을 고갈시키는 등의 심각한 장애로 이어질 수 있습니다.

많은 개발자가 단순히 os.path.exists('lock.file') 정도로 구현을 시작하지만, 실제 운영 환경에서는 프로세스가 강제 종료되었을 때 남겨진 '좀비 락' 때문에 배치가 영원히 실행되지 않는 문제에 직면하곤 합니다. 이는 수동으로 파일을 지워주기 전까지 서비스가 멈추는 결과를 초래합니다.

이 글에서는 단순한 구현부터 실무에서 발생하는 예외 상황을 방어하는 견고한 락 파일 설계 전략을 다룹니다. 배치 안정성을 높이기 위해 반드시 체크해야 할 포인트들을 정리했습니다.

락 파일 설계 대표 이미지
락 파일 설계 주제를 읽기 전에 먼저 보면 좋은 대표 이미지 · 핵심 포인트: 왜 필요한지, 구현 방식, 실패 대응

핵심 내용 먼저 보기

핵심 키워드 락 파일 설계 · 연관 검색어 락 파일 설계, Python 배치 중복 실행, 스케줄러 안정성, PID 락, 배치 프로세스 관리

배치 작업 중복 실행이 위험한 이유와 락 파일의 역할

배치 스크립트가 10분 주기로 설정되어 있는데, 특정 회차의 작업이 15분 동안 지속된다면 어떻게 될까요? 두 프로세스가 동시에 같은 DB 레코드를 수정하려고 시도하면서 데드락(Deadlock)이 발생하거나, 중복된 결과값이 생성될 위험이 큽니다. 특히 결제 처리나 알림 발송처럼 '단 한 번'의 실행이 보장되어야 하는 작업에서는 치명적입니다.

락 파일은 현재 프로세스가 실행 중임을 파일 시스템에 기록하여, 뒤이어 실행되려는 프로세스에게 "기다리거나 종료하라"는 신호를 보내는 역할을 합니다. 이는 분산 환경이 아닌 단일 서버 환경에서 가장 가볍고 효율적으로 동시성을 제어할 수 있는 방법입니다.

실무형 락 파일 구현: PID 기록과 유효성 검증

가장 기초적인 방식은 빈 파일을 만드는 것이지만, 권장되는 방식은 파일 내부에 현재 실행 중인 프로세스의 ID(PID)를 기록하는 것입니다. 이렇게 하면 나중에 락 파일이 발견되었을 때, 해당 PID를 가진 프로세스가 실제로 시스템에서 살아있는지 확인할 수 있습니다. 만약 파일은 존재하는데 해당 PID의 프로세스가 없다면, 이전 작업이 비정상적으로 종료된 것으로 판단하고 락 파일을 안전하게 삭제한 뒤 새로 시작할 수 있습니다.

파이썬의 os.getpid() 함수를 활용하면 현재 실행 중인 스크립트의 정보를 쉽게 기록할 수 있습니다. 운영 측면에서의 팁을 드리자면, 락 파일 안에 실행 시작 시간(Timestamp)을 함께 기록해두면 모니터링 시 해당 작업이 얼마나 오래 점유 중인지 파악하기 훨씬 수월해집니다.

비정상 종료 대응과 fcntl을 활용한 파일 잠금

서버가 갑자기 재부팅되거나 kill -9 명령어로 프로세스가 죽었을 때, 수동으로 락 파일을 지워줘야 하는 상황은 운영 효율을 크게 떨어뜨립니다. 이를 방지하기 위해 리눅스 시스템의 fcntl 모듈을 사용하여 파일 자체에 운영체제 수준의 잠금을 거는 방식을 고려해야 합니다. 이 방식은 프로세스가 종료되면 OS가 자동으로 잠금을 해제해주기 때문에 별도의 삭제 로직 없이도 안전합니다.

윈도우 환경까지 고려해야 하거나 더 추상화된 라이브러리를 원한다면 portalocker 같은 외부 라이브러리를 사용하는 것이 정신 건강에 이롭습니다. 직접 구현할 때는 try...finally 구문을 사용하여 작업이 성공하든 실패하든 마지막에는 반드시 락 파일을 제거하도록 코드를 구조화해야 합니다.

운영 안정성을 높이는 체크리스트와 모니터링

락 파일의 위치는 보통 /tmp/var/run 같은 임시 디렉토리를 사용하지만, 서버 재시작 시 휘발될 수 있다는 점을 계산에 넣어야 합니다. 또한, 락 파일 때문에 배치가 건너뛰어질 경우 이를 단순 로그로 남길지, 아니면 관리자에게 알림을 보낼지에 대한 정책도 필요합니다. 단순히 실행을 막는 것뿐만 아니라, 왜 막혔는지에 대한 컨텍스트를 남기는 것이 중요합니다.

만약 작업이 중단된 지점부터 다시 시작해야 하는 복잡한 로직이 필요하다면, 락 파일 설계와 더불어 상태 파일(State File) 설계를 병행해야 합니다. 락 파일이 '실행 여부'를 결정한다면, 상태 파일은 '어디까지 했는지'를 결정하기 때문입니다.

락 파일 설계는 단순해 보이지만, 예외 상황을 하나씩 따져보면 고려할 점이 꽤 많은 작업입니다. 특히 단일 서버 환경에서는 이보다 더 가성비 좋은 중복 실행 방지책은 없습니다. 하지만 파일 시스템 권한 문제나 좀비 프로세스 대응 로직이 빠지면 오히려 운영의 장애물이 될 수 있음을 명심해야 합니다.

만약 여러분의 배치가 단순히 중복 실행을 막는 것을 넘어, 끊긴 지점부터 데이터를 안전하게 다시 읽어와야 한다면 상태 관리 전략도 함께 고민해 보시기 바랍니다. 락 파일로 실행의 유일성을 보장했다면, 다음 단계는 작업의 연속성을 확보하는 것입니다.

배치 작업의 연속성을 보장하는 구체적인 방법이 궁금하다면, 이전에 다루었던 배치 스크립트 상태 파일 설계 가이드를 참고하여 전체적인 파이프라인의 안정성을 높여보세요.

자주 묻는 질문

락 파일이 남아 있어서 배치가 실행되지 않는데 어떻게 하나요?

우선 해당 락 파일에 기록된 PID가 실제 프로세스 목록에 있는지 확인하세요. 프로세스가 없다면 이전 작업이 비정상 종료된 것이므로 파일을 삭제하면 됩니다. 이를 자동화하려면 스크립트 시작 시 PID 존재 여부를 체크하는 로직을 추가해야 합니다.

여러 대의 서버에서 배치가 돌아가는데 락 파일로 해결되나요?

파일 시스템 기반의 락 파일은 단일 서버 내에서만 유효합니다. 여러 서버(분산 환경)에서 중복 실행을 막으려면 Redis의 Redlock이나 데이터베이스를 활용한 분산 락(Distributed Lock) 방식을 사용해야 합니다.

락 파일을 생성할 때 가장 권장되는 위치는 어디인가요?

리눅스 표준에 따르면 /var/run 디렉토리가 적합하지만 권한 설정이 까다로울 수 있습니다. 일반적인 배치 스크립트라면 스크립트와 동일한 경로 혹은 /tmp 디렉토리에 프로젝트명을 접두어로 붙여 생성하는 것이 관리하기 편합니다.

함께 보면 좋은 글


해시태그

#락파일설계 #Python배치중복실행 #스케줄러안정성 #PID락 #배치프로세스관리 #fcntl활용

LIST