lifecarelog
개발일지

launchd 잡이 조용히 죽는 이유, /usr/bin/python3와 Xcode 라이선스

맥 launchd 잡이 로그 없이 죽어 있다면 /usr/bin/python3가 Xcode 라이선스 게이트에 막힌 걸 의심해 보세요. plist에 DEVELOPER_DIR을 고정한 빌드로그.

5분 읽기

지난 7일 동안 저장소 두 곳에 커밋을 15건 올렸는데, 그중 제일 허무했던 건 2026-09-20 저녁의 launchd 수정이에요. 잡들이 죽어 있었거든요. 크래시도 아니고 에러 알림도 아니고, 그냥 안 돌았어요.

증상: 로그가 없는 게 로그였어요

라이프케어로그는 플랜씨(금융계산기)나 플랜비(농구 동호회 매니저) 같은 서비스를 만드는 1인 브랜드예요. 서비스는 클라우드에 있지만, 승인 배치 발송이나 블로그 발송 큐 정리 같은 자동화 몇 개는 제 맥에서 launchd로 돌려요. 무인 자동화를 직접 만들어 보니 사람이 안 보는 게 목적인데, 사람이 안 보니까 죽어도 몰라요.

직접 파 보니 원인은 파이썬 경로 하나였어요. 잡들이 /usr/bin/python3를 부르는데, 맥의 이 경로는 진짜 인터프리터가 아니라 Xcode 쪽 개발자 디렉터리로 넘겨주는 중계 실행 파일이에요. 그 앞에 Xcode 라이선스 동의 게이트가 있고요. 동의가 안 된 상태에서 터미널에 python3 --version만 쳐 봐도 버전 대신 라이선스 안내가 나오고 끝나요.

launchd 잡 시작/usr/bin/python3 호출개발자 디렉터리 확인라이선스 미동의면 종료

터미널에서는 눈에 보이니 바로 고치죠. 문제는 launchd예요. launchd는 셸 프로필을 안 읽어요. 제가 zsh에 잡아 둔 PATH도, 환경변수도 잡한테는 없어요. 그래서 대화형 셸에선 멀쩡히 도는 스크립트가 무인 경로에서만 조용히 죽어요.

수정: 잡마다 DEVELOPER_DIR을 못 박았어요

해결은 plist마다 EnvironmentVariables에 DEVELOPER_DIR을 넣는 거였어요. 어떤 개발자 디렉터리를 쓸지 중계 파일이 헤매지 않게 잡 정의 안에 고정하는 방식이에요. 승인 배치·블로그 발송·알림 발송·정리·요약 잡, 이렇게 plist 5개에 같은 키를 넣었어요. 변경은 딱 5개 파일이에요.

적용해 보면 절차는 3단계예요. plist 수정, launchctl로 내렸다 올리기, 잡 로그에서 파이썬이 실제로 실행됐는지 확인. 마지막을 빼먹으면 이번 일이 반복돼요. "등록됨"은 "돌아감"이 아니니까요.

  • launchd는 셸 프로필을 안 읽는다
  • /usr/bin/python3는 중계 파일이다
  • 무인 잡은 환경을 plist에 직접 선언한다

같은 날 두 번 더 데었어요

같은 날 밤 마이그레이션 적용 스크립트도 비슷한 이유로 커밋을 3번 했어요. 대화형 셸엔 DB 접속 문자열이 없어 미적용으로 끝났고, 설정 파일을 2곳에서 읽게 고쳤고, 마지막엔 소싱 대신 파일에서 값을 직접 뽑도록 바꿨어요. 패턴은 하나예요. 내 터미널 환경을 스크립트가 물려받을 거라고 믿는 것.

돌려 보니 교훈은 짧아요. 무인으로 돌 코드는 환경을 상속받지 말고 선언해야 해요. 그리고 죽어도 아무도 모르는 잡에는 하트비트 체크를 붙여야 하고요. 그건 사흘 뒤 커밋 얘기예요.

#launchd#macOS#Xcode#1인개발

라이프케어로그 서비스가 궁금하신가요?

AI 기반 건강·일정·재활 관리 앱을 직접 써보세요.

서비스 살펴보기

관련 글

댓글

아직 댓글이 없어요. 첫 댓글을 남겨주세요.