한 채널 상품의 기간 연장이 안 된다는 얘기가 있어서 연장 작업이 실패했겠거니 하고 조사를 시작했다. 작업 이력을 보니 생성과 갱신은 있는데 연장 작업이 0건이었다.
Table of contents
Open Table of contents
실패가 아닌 부재
실패한 것이 아니라 만들어진 적이 없었고 이 차이가 조사 방향을 완전히 바꾼다.
실패로 보고 조사하면 실패 로그를 찾게 되는데 시도 자체가 없으니 로그가 없다. 증상을 확인하기 전에 그 작업이 애초에 걸리는지를 먼저 봐야 했다.
두 경로의 서로 다른 게이트
연장 작업이 어디서 만들어지는지를 찾으니 경로가 두 곳이었다. 작업 핸들러가 작업 테이블에 적재하고 스케줄러가 나중에 실행하는 경로와 옵저버가 큐 작업을 던지는 경로다.
관리 화면에서 수동으로 연장하면 두 경로가 다 발화하는 구조였다. 첫 번째 경로의 코드를 보니 채널을 지정하지 않고 부를 때는 특정 세 채널만 통과하는 조건이 있었고 문제의 채널이 그 목록에 없었다.
부르는 방식이 바꾸는 제한
같은 핸들러에 다른 진입점도 있었는데 채널을 명시해서 부르면 목록 검사를 건너뛰고 바로 작업을 적재한다.
같은 기능인데 부르는 방식에 따라 제한이 다른 구조였다. 더 보니 특정 공급사만 예외로 허용하는 하드코딩된 조건도 있었고 어떤 사정으로 한 곳만 열어 준 것으로 보이는데 이유는 코드에 없다.
조사 중 나온 부수 버그
조사하는 중에 성격이 다른 문제가 하나 더 나왔다. 연장 함수가 허용 목록 밖의 기간 값을 받으면 조용히 반환하는데 그것을 부르는 컨트롤러가 반환값을 안 보고 이벤트를 무조건 발생시킨다.
허용 목록 밖의 값으로 요청하면 기간은 안 늘어나는데 이벤트는 발생하고 리스너가 연장 작업을 만든다. 기간은 그대로이고 작업만 쌓이는 구멍이며 이번 조사의 대상이 아니었지만 별도 항목으로 기록했다.
조용한 반환의 문제
이 부수 버그의 원인은 하나로 모인다. 함수가 아무것도 안 알리고 반환하는데 호출부가 그 반환을 보지 않는 것이다.
호출부는 성공했는지 아무것도 안 했는지를 구분할 수 없다. 최소한 안 했다는 반환값이 있어야 하고 호출부가 그것을 봐야 이 조합이 구멍이 되지 않는다.
정리
- 작업이 실패한 것이 아니라 만들어진 적 없을 수 있다
- 같은 기능에 경로가 둘 이상이고 각각 게이트가 다를 수 있다
- 대상을 명시하느냐에 따라 게이트를 건너뛰기도 한다
- 하드코딩된 예외가 있을 수 있고 이유는 코드에 안 적혀 있다
- 진단 전에 그 작업이 애초에 걸리는지를 본다
- 조용히 반환하는 함수와 반환값을 안 보는 호출부는 구멍을 만든다
- 최소한 안 했다는 반환값이 있어야 한다
- 조사 중 나온 부수 버그는 별도 항목으로 기록한다