Skip to content
isdnetworks
Go back

소진된 작업과 재현 불가

(수정됨)

Redis 리스트 큐에서 LPOP 으로 꺼낸 작업이 처리 중에 실패했는데 다시 보려 하니 이미 사라져 있었다. laravel.log 에는 오류 메시지만 남고 그 작업이 어떤 자료였는지는 어디에도 없었다.

Table of contents

Open Table of contents

원인 — 꺼내면 사라지는 구조

LPOP 은 꺼내는 순간 그 항목을 리스트에서 제거하고 처리 실패는 그다음에 일어난다. 그러면 실패한 자료가 어느 쪽에도 남지 않는다.

재현할 수 없는 실패는 원인을 찾을 방법도 고쳤는지 확인할 방법도 없다. 그래서 무엇을 고쳐야 하는지조차 정할 수 없는 상태였다.

조치 — 먼저 남기고 처리하기

꺼낸 직후에 그 자료를 queue_jobs_log 에 넣고 처리 결과에 따라 succeeded 나 failed 로 표시하게 바꿨다. 실패해도 자료가 남으므로 열어 보면 어떤 값이 빠져 있었는지가 나온다.

실제로 열어 보니 amount 필드가 아예 없었고 보내는 쪽에서 안 넣고 있었다. 남긴 자료로 그 건만 다시 큐에 넣을 수도 있게 되어 전부 다시 돌리지 않아도 됐다.

해결 — 성공해야 지우는 방식

더 근본적으로는 두 가지 방법이 있었는데 Redis 에서 LMOVE 로 처리 중 리스트에 옮겨 두고 되돌리는 감시자를 직접 짜는 것과 SQS 로 옮겨 VisibilityTimeout 안에 DeleteMessage 를 부르는 것이다. 뒤쪽을 골랐다. 이유는 AWS 공식 문서대로 받은 메시지가 큐에 남은 채 잠시 안 보이게만 되고 지우지 않으면 시간이 지난 뒤 다시 나오므로 감시자를 만들 필요가 없어서다. 대신 로컬 개발 환경이 AWS 없이는 안 도는 것과 메시지당 과금을 감수했다.

다만 계속 실패하는 항목이 반복해서 나오므로 maxReceiveCount 를 넘으면 데드레터 큐로 모으게 했다. 모아 둔 것을 사유별로 세니 대부분이 같은 오류였고 한 곳에서 오는 것이었다.

주의 — 다시 나오는 구조가 데려오는 것

다시 나오는 구조로 바꾸니 새 문제가 생겼는데 처리 중에 프로세스가 죽으면 절반쯤 진행된 상태에서 다시 나온다. 재고를 이미 뺐는데 다시 빼는 상황이 가능해진다.

그래서 queue_jobs_log.step 에 단계마다 그 단계를 했는지 기록하고 확인한 뒤에 진행하도록 만들었다. 여러 번 실행해도 결과가 같아지므로 중간에 죽어도 이어서 진행되며 이것은 다시 나오는 구조를 택하면 반드시 따라오는 작업이었다.

보관 기간과 자료 크기

자료가 큰 경우에는 전체를 남기지 않고 요약과 원본을 다시 만들 수 있는 order_id 같은 조회 조건을 함께 적었다. 그러면 기록이 커지지 않으면서도 재현 경로가 남는다.

성공한 기록과 실패한 기록의 보관 기간도 다르게 뒀다. 성공한 것은 이 작업이 처리됐느냐는 물음에 답하기 위해 한동안 두고 실패한 것은 지우지 않았다.

정리


Share this post on:

Previous Post
전수 스캔 대신 헤더
Next Post
재현 못 하는 걸 다시 쓰지 않는다