LabHub
배우기 러닝패스 코스

Debugging in Practice

The one that passes on retry — how many runs prove it is fixed

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

간헐 실패의 발생률을 시행으로 재고 추정치에 구간을 붙인다. 실패한 판에서만 참인 조건을 시행 기록에서 뽑아내고, 사이를 벌려 다시 재 관측이 증상을 지우는 것을 확인한다. 마지막으로 고쳤다고 말하려면 몇 번을 돌려야 하는지 계산하고 그 횟수를 실제로 돌려 증명한다.

왜 중요한가

"다시 해 보니 되던데요" 는 조사를 끝내는 문장처럼 들리지만 사실은 자료 두 건이다. 한 번 실패하고 한 번 성공했다. 여기서 할 일은 더 돌려 분수를 만드는 것이다. 간헐 실패가 위험한 이유는 고쳤는지를 한 번의 성공으로 판단하게 만들기 때문이다. 실패율 10%짜리를 안 고친 채 한 번 돌려 통과할 확률은 90%다. 그래서 "몇 번을 연속으로 통과시켜야 하는가" 를 먼저 계산해야 한다. 이 실습에서 어려운 것은 반복문이 아니라 판정의 근거다. 시행 횟수 없이 비율만 적으면 20번 중 2번과 200번 중 20번을 구별할 수 없고, 실패한 판의 증거를 그 자리에서 남기지 않으면 나중에 물을 대상이 없다. 채점기는 무작위에 흔들리지 않는다. 채점기가 만든 결정적인 표적(정확히 다섯 번에 한 번 실패하는 명령)에 여러분의 도구를 돌려 숫자를 대조하고, 여러분이 남긴 기록과 계산은 채점기가 같은 공식으로 다시 계산해 맞춥니다.

단계

  1. /root/flaky/gen_flaky.py 를 만들어 실행해 /root/flaky/job.py 를 만드세요.
  2. /root/flaky/measure.py 로 job.py 를 200번 이상 돌려 /root/flaky/rate.json 에 실패율과 윌슨 구간을 적으세요.
  3. /root/flaky/plan.py/root/flaky/runs_needed.json 으로 신뢰수준별 필요한 연속 통과 횟수를 구하세요.
  4. /root/flaky/collect.py 로 시행마다 증거를 남겨 /root/flaky/facts.jsonl 을 만들고, 실패할 때만 참인 것을 /root/flaky/only_when_fail.json 에 적으세요.
  5. 시행 사이를 벌려 다시 재고 /root/flaky/observer.json 에 두 측정을 나란히 적으세요.
  6. /root/flaky/policy.json 에 재시도 예산과 격리 기준, 초록 판정에 필요한 연속 통과 횟수를 계산으로 정하세요.
  7. 고친 판을 계산된 횟수만큼 돌려 /root/flaky/proof.json 에 증거를 남기세요.
  8. /root/flaky/summary.json/root/flaky/flaky_report.md 에 네 절로 보고하세요.

참고

간헐 실패하는 작업 손에 쥐기

/root/flaky/gen_flaky.py 를 만들어 실행해 /root/flaky/job.py 를 만드세요. 그런 다음 job.py 를 손으로 여러 번 돌려 되기도 하고 안 되기도 하는 것을 직접 보세요.

이 스크립트를 그대로 저장해 실행하면 됩니다. 만들어진 job.py 를 연속으로 열 번쯤 돌려 보세요. 종료 코드가 0 인 판과 3 인 판이 섞여 나옵니다. 몇 번에 한 번인지는 아직 세지 마세요 — 그것이 2단계입니다.

가끔을 분수로 바꾸기

/root/flaky/measure.py 를 만들어 job.py 를 200번 이상 돌리고 /root/flaky/rate.json 에 command·trials·failures·rate·ci_low·ci_high·gap_ms 를 적으세요. 구간은 95% 윌슨 점수 구간입니다.

실패는 종료 코드가 0 이 아닌 것으로 셉니다. 비율만 적으면 20번 중 2번과 200번 중 20번을 구별할 수 없으니 시행 횟수를 함께 남기세요. 윌슨 구간의 두 식은 참고 절에 있습니다 — 실패가 0건이어도 폭이 0 이 되지 않는 것이 이 구간을 쓰는 이유입니다.

몇 번을 돌려야 고쳤다고 말할 수 있나

/root/flaky/plan.py 를 만들고 /root/flaky/runs_needed.json 에 observed_rate 와 신뢰수준 0.9·0.95·0.99 각각의 runs 를 담은 table, 그리고 chosen(0.95)을 적으세요.

안 고친 채 n 번 모두 통과할 확률은 (1-p)의 n 제곱입니다. 그 확률을 1-c 이하로 누르는 가장 작은 n 이 답이고, 로그를 취하면 한 줄로 나옵니다. 올림을 잊지 마세요 — 소수 번 돌릴 수는 없습니다.

실패한 그 자리에서 증거 남기기

/root/flaky/collect.py 로 60번 이상 돌려 /root/flaky/facts.jsonl 을 만들고, /root/flaky/only_when_fail.json 에 trials·failures·exit_codes_on_failure·exit_codes_on_success·token·failure_trials 를 적으세요. token 은 모든 실패의 표준오류에 있고 어떤 성공에도 없는 낱말입니다.

간헐 실패는 다시 부를 수 없습니다. 시행마다 종료 코드와 표준오류를 그 줄에 적어 두어야 나중에 물을 대상이 생깁니다. token 은 실패 기록을 눈으로 훑으면 바로 보입니다 — 대문자로 된 한 낱말입니다. 성공 기록에는 그 낱말이 없어야 token 이 됩니다.

관측이 증상을 지운다

시행 사이를 2000밀리초 이상 벌려 20번 이상 다시 재고, /root/flaky/observer.json 에 fast 와 slow 두 측정(trials·failures·rate·gap_ms)과 changed 를 적으세요. 느리게 재면 실패가 0건이어야 합니다.

로그를 붙이고 한 단계씩 돌리면 증상이 사라지는 일이 흔합니다. 타이밍에 달린 조건이 느려지는 순간 성립하지 않기 때문입니다. 사라졌다는 사실 자체가 단서입니다 — 원인이 속도나 순서에 있다는 뜻이니까요. measure.py 의 --gap-ms 로 같은 일을 만들 수 있습니다.

재시도 예산과 격리 기준 계산하기

/root/flaky/policy.json 에 observed_rate·confidence(0.95)·green_runs_required·retry_budget·quarantine_after 를 적으세요. retry_budget 은 p^(r+1) <= 0.01 을 만족하는 가장 작은 r 이고, quarantine_after 는 1 이상의 정수입니다.

재시도는 잘못된 대응이 아니지만 횟수에는 근거가 있어야 합니다. 실패율을 알면 '모두 실패할 확률' 을 계산할 수 있고, 거기서 예산이 나옵니다. 격리를 안 하면 사람들은 실패를 무시하는 습관을 배우고, 그 습관은 진짜 실패에도 적용됩니다.

고쳤다를 근거와 함께 주장하기

고친 판(--fixed)을 3단계에서 계산한 횟수 이상 돌려 /root/flaky/proof.json 에 command·required·trials·failures 를 적으세요. failures 는 0 이어야 하고 trials 는 required 이상이어야 합니다.

한 번 통과한 것은 증거가 아닙니다. 실패율 p 인 문제를 안 고친 채 통과할 확률이 이미 1-p 이기 때문입니다. 3단계의 chosen.runs 를 그대로 가져와 그만큼 돌리고, 그 기록을 파일로 남기세요. 채점기는 같은 명령을 직접 다시 돌려 봅니다.

확률을 한 장으로 보고하기

/root/flaky/summary.json 에 trials·failures·rate·ci_low·ci_high·token·green_runs_required·proof_trials·observer_changed 를 적고, /root/flaky/flaky_report.md## 얼마나 자주인가 ## 실패할 때만 참인 것 ## 관측이 바꾼 것 ## 고쳤다고 말하려면 네 절로 보고하세요.

보고서의 값어치는 결론이 아니라 숫자에 있습니다. 시행 횟수와 실패 횟수, 구간, 필요한 연속 통과 횟수를 모두 적으세요. 관측을 붙였을 때 사라졌다는 사실도 단서이므로 함께 적습니다.