디지털 가든
launchd 통로: 일흔하나의 푸른불과 육안에 보이지 않는 하나의 버그
「이 길은 통하지 않는다」는 판언을 쓰는 가장 완고한 방법은, 통로의 부재를 길의 부존재로 부기하는 것이다.
넷이즈 동굴의 검사는 꼬박 두 라운드나 막혀 있었다——「제6항의 검사는 어떻게 해도 통과하지 못한다」. 낡은 판언이 돌린 것은 환경. 사용자는 다만 한 마디로 답했을 뿐이다——「Mac에는 15분을 버티는 안정된 통로가 분명히 있을 거야. 다른 프로젝트는 30분씩이나 잘 굴러가잖아.」
1. 통로의 고고
고고대는 Mac의 기반 시설을 재답사하고, 진상을 파냈다——CI의 장시간 태스크는 상주 데몬 ~/bin/build-worker.py(launchd 위탁, com.build.worker.plist)에 의존한다. 그래서 30분 빌드가 당연하다. 자신의 검사 주행이 실패한 이유는——SSH 세션이 끊기면 자식 프로세스는 SIGHUP에 끌려가고, nohup은 구하지 못하며, macOS에는 setsid가 없다.
macOS의 원생 해법이 눈앞에 횡자돼 있었다——launchctl submit. 명령을 launchd에 넘겨, SSH 세션의 수명과 완전히 분리한다. 작업은 launchd의 이름으로 굴러가고(PID 19023), 다섯 개의 결과 XML이 차례로 착륙, 15분짜리 Robolectric 첫 주행이 처음으로 전 구간을 달렸다.
2. 59통과, 5패배
제1라운드——59 통과, 5 실패——걸린 것은 바로 새로 쓴 Robolectric UI 검사 클래스. 원인을 한 장씩 벗겼다——Robolectric은 manifest에 따라 NcmApplication을 인스턴스화하고, 그 onCreate는 startKoin()을 호출한다——같은 JVM에서 두 번째 유즈 케이스를 돌리면 Koin은 이미 등록돼 있어, 다시 시작하면 KoinAppAlreadyStartedException을 던진다. 수법은 한 줄——유즈 케이스마다 @After { stopKoin() }(커밋 cd4fcef).
제2라운드——71개 검사 전부 통과, 0 실패.
| 검사 클래스 | 유즈 케이스 수 |
|---|---|
| LrcParseTest | 23 |
| BuildOrdersTest | 23(심동 모드, 다중 삽입 포함) |
| SongListFilterTest | 13 |
| SongListFilterBarTest(Robolectric/Compose UI) | 6 |
| CodeErrorTest | 6 |
3. 이 버그의 무게
검시관은 회장에서 무거운 한 마디를 했다——이 한 주행이 잡아낸 것은 육안으로는 절대 보이지 않는 버그다. 통로가 없으면, 이批의 검사는 영원히 집행되지 않는다——Mac CI는 assembleReleaseRenamed만 돌고 test 의존을 결코 해소하지 않는다. 그러므로 지난 라운드의「검사 미검증」 보고는 옳았다——그러나 길이 존재하지 않아서가 아니라, 닦는 사람이 아직 문을 찾지 못했을 뿐이다. 문만 찾으면 문제는 즉시 형태를 드러낸다.
4. 정직한 경계
같은 밤의 또 다른 기능「곡 전환의 페이드 인」에도, 정직한 경계 설명서가 곁들여졌다——진정한 crossfade는 두 갈래 오디오 스트림의 겹침, 스스로 믹싱하는 두 플레이어 인스턴스를 요한다. 단일 ExoPlayer로는 할 수 없다——구조적 대가와 기능의 가치가 비례하지 않는다. 만든 것은「새 곡이 올라오는」 것으로, 부드러운 전이일 뿐, 엄밀한 의미의 crossfade가 아니다. 그리고 그 음향의 순간의 페이드는 검증할 수 없다——에뮬레이터는 볼륨의 램프를 구분하지 못하며, volume 곡선을 관측할 interface도 없다. 검증할 수 없는 것은, 검증할 수 없다고 단언한다.
이번 라운드는 총 14 커밋, 마지막 Mac 빌드는 EXIT 0, 6라운드의 컴파일 오류를 일일이 수정(괄호를 잃은 mutableListOf, 존재하지 않는 getMaxGain(), 닻을 잘못 고른 import, 분기를 빠뜨린 when, 세 개의 테스트 의존, 전정식 호출이 안 되는 확장 함수). 검사를 위해 Mac에 만든 임시 클론과 스크립트는 쓴 뒤 즉시 태웠다——디스크는 39%로 돌아갔다.
실제 좌표
- 통로:
~/bin/build-worker.py(launchd 위탁) +launchctl submit(SSH 세션 수명의 밖으로.nohup은 SIGHUP으로 죽고, macOS에는setsid가 없음) - 검사 명령:
export ANDROID_HOME=/Users/min/Library/Android/sdk && ./gradlew :app:testDebugUnitTest - 전적: 첫 주행 59통과 5실패(
KoinAppAlreadyStartedException——Robolectric이NcmApplication을 인스턴스화 →startKoin중복) →@After stopKoin()으로 수정 → 71/71 전록 - 경계: 곡 전환 페이드 ≠ crossfade(이중 플레이어 믹싱 필요); 볼륨 램프는 검증 불가(에뮬레이터에 관측 interface 없음)
- 규율: 14 커밋, 6라운드 컴파일 오류 수정, Mac만; 임시 클론은 정리, 디스크 39%
댓글