배치 실패를 알리게 만들어 뒀다. 며칠째 실패하고 있었는데 아무도 몰랐다. 알림은 나가고 있었다.
Table of contents
Open Table of contents
나가는 것과 보는 것은 달랐다
설정을 봤다.
$config['alert_email'] = 'dev@example.com';
그 주소로 보내던 사람이 몇 달 전에 퇴사했다. 계정이 정지돼서 메일이 반송되고 있었고 반송 메일도 그 주소로 가니 아무도 안 본다.
발송 기록에는 성공으로 남아 있었다. mail() 이 true 를 돌려줬기 때문이다. 이 함수는 넘기지 못했을 때만 false 와 E_WARNING 을 낸다.
매뉴얼도 그 반환값이 배달을 수락했다는 뜻일 뿐 실제 목적지에 닿는다는 뜻은 아니라고 못 박아 뒀다. 알림이 나가는 것과 사람이 보는 것은 다르다.
만들 때 담당자 개인 주소를 적었던 것이 원인이었다. 만든 시점에는 맞았지만 사람이 바뀌면서 틀린 값이 됐다. 설정이 낡는다는 것을 그때까지 생각해 본 적이 없었다.
받는 곳을 바꿨다
개인 주소 대신 여러 명이 보는 곳으로 바꿨다.
$config['alert_email'] = 'ops@example.com'; // 목록 주소
사람이 바뀌어도 주소가 안 바뀐다. 새로 온 사람을 그 목록에 넣는 것으로 끝난다.
수신자 목록은 설정 파일에 두고 코드에서 뺐다. 사람이 바뀔 때마다 배포하지 않아도 된다. 목록에 누가 들어 있는지 확인하는 것도 정기 항목에 넣었다.
검증 — 도착하는지 확인했다
받는 곳을 바꿔도 실제로 오는지는 별개다. 주기적으로 시험 알림을 보내게 했다.
0 9 * * 1 /opt/tools/alert-test.sh
매주 월요일 아침에 한 통 온다. 이게 안 오면 알림 경로에 문제가 있는 것이다.
[알림 점검] 2014-11-05 09:00
이 메일이 오지 않으면 알림 경로를 확인하십시오.
지난주 알림 발송: 3건
지난주 발송 건수를 같이 넣었다. 실제로 한 번 안 와서 확인해 보니 php.ini 의 sendmail_path 가 바뀌어 있었다.
발송 결과도 기록했다.
$ok = mail($to, $subject, $body, $headers);
$this->db->insert('alert_log', [
'to_addr' => $to,
'subject' => $subject,
'sent' => $ok ? 1 : 0,
'reg_date' => date('Y-m-d H:i:s'),
]);
mail() 이 false 를 돌려주면 발송 자체가 실패한 것이라 이건 잡힌다. 발송은 됐는데 상대가 안 받는 경우는 못 잡으니 시험 알림이 필요했다.
반송 메일도 확인했다. 없는 주소로 보내면 MAILER-DAEMON 이 되돌려 주고 SMTP 규격에서 550 이 그 주소를 못 찾았다는 뜻이다.
그것이 어디로 가는지는 Return-Path 가 정한다. mail() 은 다섯 번째 인자에 -f 를 줘야 그 값이 잡히고 From 헤더만 바꿔서는 반송이 엉뚱한 곳으로 간다. 그 주소를 우리가 보는 곳으로 돌리고 나서야 반송이 눈에 들어왔다.
수준과 할 일
메일 하나에 의존하는 것도 문제였다.
if ($level === 'critical') {
sendSms($phone, mb_substr($msg, 0, 80));
}
sendMail($to, $subject, $msg);
심각한 것은 문자로도 보냈다. 두 경로가 다 죽을 확률은 낮다. 문자는 짧아서 핵심만 보내고 상세는 메일로 보냈다.
반대 경우도 있었다. 알림이 너무 많아서 아무도 안 읽는 것이다.
critical 즉시 문자 + 메일 서비스 중단, 자료 손실 위험
error 메일 배치 실패, 연동 오류
warning 일일 요약에 포함 재시도 증가, 사용량 경고
info 로그만 정상 동작 기록
warning 은 개별로 안 보내고 하루 한 번 묶어서 보냈다.
[일일 요약] 2014-11-04
배치 5종 정상
연동 재시도 증가: delivery (평균 2.4회)
디스크 사용률: srv-01 82%
이렇게 나누니 critical 이 오면 실제로 본다.
알림에 무엇을 해야 하는지도 적었다. 배치 실패만 오면 무엇을 할지 모른다.
[오류] 정산 배치 실패
시각: 2014-11-05 03:14
대상: settle_daily (2014-11-04 분)
오류: mysqldump: Access denied for user 'batch'
확인:
1. /opt/batch/settle.log 마지막 50줄
2. 계정 비밀번호 변경 여부
재실행:
/opt/batch/settle.sh 2014-11-04
확인할 것과 다시 돌리는 방법을 붙여 칠 수 있는 형태로 넣으니 받은 사람이 바로 움직였다.
정리
- 알림이 나가는 것과 사람이 보는 것은 다르다
mail()의true는 배달 수락이지 도착이 아니다- 개인 주소는 사람이 바뀌면 아무도 안 보는 곳이 된다
- 여러 명이 받는 목록 주소로 보내고 그 목록을 설정에 둔다
- 주기적으로 시험 알림을 보낸다. 안 오면 경로에 문제가 있다
Return-Path는mail()의-f인자로 잡는다.From만으로는 안 된다- SMTP 의
550반송은 그 주소가 없다는 뜻이다 - 발송 결과를 기록하되 발송 성공이 도착을 뜻하지 않는다
- 심각한 것은 경로를 둘로 나눈다
- 알림이 너무 많으면 안 읽는다. 수준을 나누고 낮은 것은 묶어서 보낸다
- 알림에 확인할 것과 다시 돌리는 명령을 적는다