LabHub
Get started
배우기 러닝패스 코스

Building an EAI Middleware Layer

Receive the Claim File, Check It, Load It Once

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 로 만듭니다.