LabHub
学习 学习路径 课程

集成与部署

我们的日志全是成功,对方却少了十二笔

在 LabHub 中继续学习

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

목표

묶어 보낸 요청에서 몇 건만 실패하는 상황을 다룬다. 건별 결과를 우리 쪽에 기록하고, 다시 보낼 실패와 고쳐야 할 실패를 가르고, 실패분만 재전송하고, 마지막에 보낸 쪽과 받은 쪽의 건수와 합계를 맞춰 보는 대사표를 만든다.

왜 중요한가

묶음 전송 API 는 요청 하나에 200 을 주면서 본문 안에 건별 결과를 담는다. HTTP 의 관점에서 200 은 옳다 — 2xx 는 요청을 받아 수락했다는 뜻이지 요청 안의 모든 항목이 성공했다는 뜻이 아니다. 그래서 호출한 쪽이 상태 코드만 보면 실패한 몇 건은 아무 데도 남지 않는다. 오류도 경보도 없이 며칠이 쌓이고, 상대 쪽 숫자와 맞춰 보다가 발견된다. 고치는 순서는 넷이다. 건별로 기록하고, 실패를 두 갈래로 가르고, 실패분만 다시 보내고, 양쪽 수를 맞춰 본다. 특히 세 번째가 중요하다 — 묶음 전체를 다시 보내면 이미 들어간 건이 두 번 들어간다. 재시도의 단위는 묶음이 아니라 건이다. 채점기는 여러분의 문장을 믿지 않는다. 파트너 서버를 채점기가 고른 포트에 새로 띄우고, 여러분의 발신함과 전송기를 채점기의 데이터베이스에 대고 실제로 돌려 상대 원장과 대조한다.

단계

  1. /root/recon/receiver.py 를 만들어 포트 8010 에 띄우고, /root/recon/gen_outbox.py 로 보낼 것 120건을 /root/recon/outbox.db 에 만드세요.
  2. /root/recon/send.py--naive 로 상태 코드만 보고 보낸 뒤, 우리 기록과 상대 원장의 차이를 /root/recon/naive.json 에 적으세요.
  3. send.py 가 건별 결과를 읽어 sent 표에 status·reason·attempts 로 기록하게 하세요.
  4. /root/recon/classify.py 를 만들어 실패 이유를 다시 보낼 것과 고칠 것으로 가르게 하세요.
  5. send.py 의 --retry 가 다시 보내도 되는 건만 골라 재전송하게 하세요.
  6. /root/recon/recon.py 로 보낸 쪽과 받은 쪽을 대조해 /root/recon/recon_result.json 을 만드세요.
  7. 남은 건의 처리 계획을 /root/recon/unresolved.json 에 적으세요.
  8. /root/recon/recon_report.md 에 네 절로 보고하세요.

참고

묶음 수신 파트너와 보낼 것 120건

/root/recon/receiver.py 를 만들어 포트 8010 에 띄우고, /root/recon/gen_outbox.py 를 만들어 실행해 /root/recon/outbox.db 에 120건을 넣으세요. 계좌가 틀린 것 5건, 금액이 0 인 것 3건, 97의 배수인 것 4건이 섞여 있어야 합니다.

파트너는 요청 자체에는 늘 200 을 주고 실패를 본문의 results 안에 담습니다. 거절 판정은 금액·계좌·중복·일시 보류 순서로 봅니다. 발신함은 보낼 것과 보낸 결과를 나눠 두 표로 만드세요 — 한 표에 섞으면 '보낸 적 없는 것' 과 '보내서 실패한 것' 이 구별되지 않습니다.

상태 코드만 보면 무엇을 놓치나

/root/recon/send.py--naive 를 만들어 상태 코드만 보고 전부 성공으로 세게 하세요. 그 결과와 상대 원장의 차이를 /root/recon/naive.jsonbatches·http_ok·assumed_sent·partner_rows·gap 으로 적으세요.

요청은 정말로 성공했습니다. 실패는 본문 안에 있습니다. 우리 기록이 120건 성공인데 상대 원장에는 몇 행이 있는지 세어 보면 차이가 그대로 드러납니다. 이 단계에서는 sent 표에 아무것도 적지 않습니다.

건별 결과를 우리 쪽에 남기기

send.py 가 응답 본문의 results 를 읽어 건마다 sent 표에 status·reason·attempts 를 남기게 하세요. 성공도 실패도 모두 기록해야 합니다. 두 번째 실행은 이미 보낸 건을 다시 보내지 않아야 합니다.

실패한 것만 적으면 '보낸 적이 없는 것' 과 '보내서 성공한 것' 이 구별되지 않습니다. 응답의 results 순서가 요청 순서와 같다고 가정하지 말고 item_id 로 맞춰 읽는 편이 안전합니다. 아직 보내지 않은 건은 outbox 에는 있고 sent 에는 없는 건입니다.

다시 보낼 것과 고칠 것

/root/recon/classify.py 를 만들어 --reason 으로 받은 이유를 {"retryable": ..., "action": ...} 로 판정하게 하세요. action 은 requeue·fix_data·ignore 셋이고, 모르는 이유는 다시 보내지 않는 쪽으로 답합니다.

일시 보류는 그대로 다시 보내면 풀립니다. 모르는 계좌와 잘못된 금액은 몇 번을 보내도 같은 답이 오므로 사람이 데이터를 고쳐야 합니다. 이미 상대 원장에 들어간 건은 다시 보낼 것도 고칠 것도 없습니다. 이 분류가 없으면 고칠 수 없는 건들이 큐에서 영원히 돕니다.

묶음이 아니라 건 단위로 다시

send.py 의 --retry 가 앞서 거절된 건 가운데 다시 보내도 되는 것만 골라 재전송하고 결과를 sent 에 갱신하게 하세요. 이미 성공한 건은 절대 다시 보내면 안 됩니다.

묶음 전체를 다시 보내면 이미 들어간 건이 두 번 들어갑니다. 상대가 중복을 막아 주면 다행이고 안 막아 주면 우리가 사고를 냅니다. 분류기를 불러 retryable 인 것만 고르고, attempts 를 올려 두어야 몇 번째 시도인지 나중에 압니다.

보낸 쪽과 받은 쪽을 맞춰 본다

/root/recon/recon.py 로 발신함·우리 기록·상대 원장을 대조해 /root/recon/recon_result.json 을 만드세요. 건수뿐 아니라 합계와 양쪽에만 있는 건까지 보아야 하고, 모두 맞을 때만 balanced 가 true 입니다.

건수만 맞춰 보면 한 건이 빠지고 다른 한 건이 두 번 들어간 경우를 놓칩니다. 우리가 성공으로 적은 id 집합과 상대 원장의 id 집합을 서로 빼 보면 어느 쪽에만 있는지 바로 나옵니다. 아직 보내지 않은 건이 있는지도 함께 셉니다.

남은 건에는 주인이 있어야 한다

/root/recon/unresolved.json 에 아직 해결되지 않은 건들을 total·by_action·items(item_id·reason·action·owner)로 적으세요. action 은 분류기의 답과 같아야 하고 owner 는 비워 둘 수 없습니다.

'고쳐야 함 8건' 을 만들어 놓고 누가 고칠지 안 적으면 그 8건은 영원히 남습니다. 대사표의 마지막 칸은 사람이나 팀 이름입니다. items 는 sent 표에서 거절로 남은 건들을 그대로 꺼내 만들면 됩니다.

대사 보고서

/root/recon/recon_report.md## 무엇을 놓치고 있었나 ## 건별 결과를 읽고 나서 ## 다시 보낼 것과 고칠 것 ## 대사표와 남은 것 네 절로 적으세요. naive.json 과 recon_result.json 의 숫자가 본문에 들어가야 합니다.

읽는 사람은 '우리 로그에는 다 성공인데요' 라고 말한 사람입니다. 그 로그가 거짓말이 아니라 요청의 상태 코드만 본 것이라는 점을 먼저 설명하세요. 그다음 이유별 건수와 대사표의 두 숫자를 보여 주면 됩니다.