배포와 인프라3 분 읽기

내 자동화를 깨뜨린 macOS launchd 함정들

BSD 도구, 한국어 로케일, launchd의 최소 환경이 각각 예약 작업을 깨뜨렸고 에러 메시지는 진짜 원인을 설명하지 않았다. 함정 다섯과 해결.

#macos#launchd#automation#debugging
개념 도식: macOS launchd 함정
글 내용을 요약한 개념 도식.

상시 켜둔 맥에서 예약 작업을 돌립니다. 이 함정들은 실패가 진짜 원인을 가리키지 않아 각각 디버깅 세션을 잡아먹었습니다.

1. ps -o etimes는 macOS에 없다

BSD psetimes 키워드가 없습니다 — 리눅스 procps 전용. ps -p PID -o etime=을 쓰고 [[DD-]HH:]MM:SS 형식을 파싱하세요. 리눅스에서 되는 코드가 여기선 조용히 실패합니다.

2. 한국어 로케일에서 pgrep이 실패한다

셸 로케일이 ko_KR.UTF-8이면 pgrep -f <pattern>illegal byte sequence를 냅니다. 서브프로세스에 C 로케일을 강제하세요:

env = {**os.environ, "LC_ALL": "C", "LANG": "C"}
subprocess.run([...], env=env)

3. launchd의 PATH엔 /usr/sbin이 없다

PATH=/usr/local/bin:/usr/bin:/bin plist는 /usr/sbin/lsof를 못 찾습니다 — FileNotFoundError. lsof·dscl·vm_stat·sysctl 등은 절대경로를 쓰거나 plist PATH에 /usr/sbin을 추가하세요.

4. pgrep -f는 작업 디렉토리를 매칭 안 한다

macOS pgrep -f는 풀 커맨드라인만 보고 cwd는 안 봅니다. 작업 디렉토리로만 식별되는 봇(특정 폴더의 python main.py)은 lsof -a -p PID -d cwd 후처리 필터가 필요합니다.

5. 로그인 화면에선 LaunchAgent가 기동 안 한다

재부팅 후 맥이 macOS 로그인 화면에 머물면 gui/501 도메인이 없어 LaunchAgent가 하나도 로드되지 않습니다 — 모든 예약 작업 다운. SSH로 bootstrap도 안 됩니다(I/O 에러로 실패). 우회는 누군가 로그인할 때까지 plist 명령을 nohup으로 수동 재현 — 그리고 진짜 launchd가 기동하면 스스로 종료하는 감독 스크립트.

솔직한 부분

전부 같은 모양입니다: 도구가 launchd의 최소 환경·비C 로케일·BSD 유저랜드에서 제 인터랙티브 셸과 다르게 동작하는데 — 에러는 제 코드를 탓합니다. 예약 작업이 실패하는데 같은 명령이 터미널에선 되면, 로직이 아니라 환경을 의심하세요: PATH, 로케일, GUI 세션, BSD-vs-GNU 플래그 순으로.

관련 글