LabHub
はじめる
배우기 러닝패스 코스

EAI 中間層をつくる

請求ファイルを受け取り、照合し、一度だけ入れる

LabHub 에서 이어서 보기

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

목표

제휴 보험사의 청구 파일을 SFTP 로 안전하게 받아(완료 플래그·체크섬·원자적 이름 바꾸기·재실행 안전), 헤더·트레일러를 검증하고, 파일 단위로 적재한 뒤 우리 접수 원장과 대사한다.

왜 중요한가

파일 연동의 사고는 경계에서 난다 — 쓰는 중인 파일, 전송 중 손상, 재실행으로 인한 이중 적재, 맞춰 보지 않은 숫자. 네 가지 모두 에러 없이 조용히 지나가고, 결산이나 고객 민원에서야 드러난다.

단계

  1. python3 /opt/lab/fixtures/eaimw/batch/partner_drop.py --out /root/eaimw/batch/remote --day 20260923 으로 파트너의 원격 디렉터리를 만들고, sftp -D /usr/lib/openssh/sftp-server -b <배치파일> 로 그 디렉터리를 cd 한 뒤 ls -l 한 출력을 그대로 /root/eaimw/batch/remote-ls.txt 에 저장한다.
  2. /root/eaimw/batch/fetch.sh 를 쓴다. 환경변수 REMOTE_DIR(기본 /root/eaimw/batch/remoteLOCAL_DIR(기본 /root/eaimw/batch/inboxQUAR_DIR(기본 /root/eaimw/batch/quarantine)를 읽고, SFTP 로 원격 목록을 받아 <파일>.done 이 있는 .dat LOCAL_DIR 로 받는다.
  3. 플래그 내용(<바이트수> <sha256>)과 받은 파일을 대조한다. 다르면 그 파일을 QUAR_DIR 로 옮기고(LOCAL_DIR 에 두지 않는다) 나머지는 계속 처리한 뒤, 마지막에 0 이 아닌 코드로 끝난다.
  4. 받는 동안은 LOCAL_DIR 안의 <파일>.part 로 받고, 검증이 끝나면 최종 이름으로 바꾼다. 받은 뒤에는 SFTP 로 원격 파일과 플래그 이름 끝에 .fetched 를 붙인다. 다시 돌리면 아무것도 받지 않고 0 으로 끝난다.
  5. /root/eaimw/batch/check.py <파일>: 줄마다 60바이트(EUC-KR, 줄 끝 LF), 첫 줄 H·마지막 줄 T·사이 D, H 일자 = 파일명 일자, T 건수·합계 = D 의 건수·합계. 맞으면 OK <건수> <합계> 와 종료 0, 틀리면 첫 줄 E <사유> 와 종료 2.
  6. /root/eaimw/batch/load.py --db <경로> <파일>: 검증을 통과한 파일만 SQLite 테이블 claims(claim_no 기본키, policy_no, amount, claim_date, insured, src_file) 에 적재하고 load_log(file 기본키, records, total, loaded_at) 에 남긴다. 같은 파일은 다시 넣지 않고(0 으로 끝남), 파일 하나는 트랜잭션 하나(전부 또는 전무).
  7. /root/eaimw/batch/recon.py --db <경로> --ledger <원장CSV> --out <결과CSV>: claims 와 원장(claim_no,amount)을 청구번호로 맞춰 claim_no,status,partner_amount,our_amount 를 청구번호순으로 쓴다. status 는 MATCHED·ONLY_PARTNER·ONLY_OURS·AMOUNT_MISMATCH, 없는 쪽 금액은 빈칸. 끝으로 오늘 파일(CLM_401_20260923.dat)을 받아 적재하고, partner_drop.py --ledger /root/eaimw/batch/ledger.csv --day 20260923 원장과 대사한 결과를 /root/eaimw/batch/recon.csv 에 낸다.

참고

SFTP 로 원격을 본다

partner_drop.py 로 원격 디렉터리를 만들고 sftp -D 배치로 나열한 출력을 /root/eaimw/batch/remote-ls.txt 에 저장한다.

배치 파일에 cd 와 ls -l 두 줄을 적고 sftp -D /usr/lib/openssh/sftp-server -b 배치파일 로 돌립니다. 출력을 그대로 리다이렉트하세요.

플래그가 있는 파일만 받는다

/root/eaimw/batch/fetch.sh 가 REMOTE_DIR 에서 .done 이 있는 .dat 만 LOCAL_DIR 로 받는다.

먼저 ls -1 로 이름 목록을 받아 두고, 각 .dat 에 대해 같은 이름 + .done 이 목록에 있는지 봅니다(grep -qx). 받기는 get 원격 로컬.

체크섬이 다르면 격리한다

플래그의 바이트 수·sha256 과 받은 파일을 대조해, 다르면 QUAR_DIR 로 옮기고 마지막에 0 이 아닌 코드로 끝난다.

플래그도 받아서 read -r size sha 로 읽고 stat -c %s, sha256sum 과 비교합니다. 한 파일이 깨졌다고 나머지를 멈추지 말고, 종료 코드만 기억해 두세요.

임시 이름으로 받고, 원격에 표시한다

LOCAL_DIR 안의 .part 로 받아 검증 후 이름을 바꾸고, 원격 파일·플래그에 .fetched 를 붙여 재실행을 안전하게 한다.

임시 파일은 최종 디렉터리와 같은 곳에 둬야 rename 이 원자적입니다. 원격 표시는 SFTP 의 rename 명령입니다.

헤더와 트레일러를 맞춰 본다

/root/eaimw/batch/check.py <파일> 이 줄 길이(바이트)·H/D/T 구조·일자·건수·합계를 검증한다(OK <건수> <합계> / E <사유> 와 종료 2).

파일을 rb 로 읽어 줄로 나누고 len(줄)==60 을 봅니다. T 의 건수(1~8)·합계(8~23)를 D 에서 직접 센 값과 비교합니다. 이름은 euc_kr 로 디코드합니다.

파일 단위로 한 번만 넣는다

/root/eaimw/batch/load.py --db <경로> <파일> 이 검증된 파일만 트랜잭션 하나로 적재하고 load_log 로 재적재를 막는다.

isolation_level=None 으로 열고 BEGIN … COMMIT 을 직접 씁니다. 청구번호 기본키 충돌(IntegrityError)이 나면 ROLLBACK 해서 앞의 행까지 되돌립니다.

우리 원장과 대사한다

/root/eaimw/batch/recon.py 로 claims 와 원장을 대사하고, 오늘 파일 기준 결과를 /root/eaimw/batch/recon.csv 에 낸다.

두 쪽 청구번호의 합집합을 정렬해 돕니다. 한쪽만 돌면 반대쪽에만 있는 건을 놓칩니다. 원장은 partner_drop.py --ledger 로 만듭니다.