후행 처리 넘버링 서비스 개발
후행 처리 넘버링 서비스는 Bxm Bean 을 개발하여야 하며, Bean 입력 아규먼트는 bxm.deferred.data.IDeferredMainInfo 을 사용하여야 한다.
아래의 그림은 후행 처리 넘버링 서비스 입출력을 나타낸다. 넘버링 서비스 입력 값은 후행 처리 메인 테이블의 값을 전달해준다.
아래 표는 입력 DTO 의 컬럼 명에 대해 설명한 것이다.
컬럼(물리 명) | 컬럼(논리 명) | 타입 |
---|---|---|
domainId |
도메인 ID |
String |
deferredId |
후행 처리 ID |
String |
trxCd |
거래코드 |
String |
bxmAppId |
BXM어플리케이션ID |
String |
svcNm |
서비스 명 |
String |
opNm |
오퍼레이션 명 |
String |
deferredNm |
후행 처리 명 |
String |
useYn |
사용여부 |
String |
errStopYn |
에러중지여부 |
String |
errSkipYn |
에러SKIP여부 |
String |
nodeExecYn |
노드별실행여부 |
String |
startTypeCd |
시작유형코드 |
String |
svcProcCd |
서비스처리코드 |
String |
deferredTranCd |
후행처리트랜잭션코드 |
String |
execIntervalSec |
실행주기 초 |
Integer |
delayIntervalSec |
지연주기 초 |
Integer |
fetchCnt |
조회 건수 |
Integer |
parllExecCnt |
병렬실행 수 |
Integer |
targetTableNm |
대상테이블 명 |
String |
dayTableYn |
일별테이블여부 |
String |
targetColumnNm |
대상컬럼 명 |
String |
targetStdDtNm |
기준일자 명 |
String |
tableReaderBeanNm |
테이블리더빈 명 |
String |
tableNumberingUseYn |
테이블채번사용여부 |
String |
tableNumberingBxmAppId |
BXM어플리케이션ID |
String |
tableNumberingBeanNm |
테이블채번빈 명 |
String |
errReprocCnt |
재처리횟수 |
Integer |
reprocAbleErrCd |
재처리가능에러코드 |
String |
modifyUserId |
사용자ID |
String |
modifyOccurDttm |
발생 일시 |
String |
아래의 예는 후행 처리 넘버링 빈 개발 샘플이다.
@Override
public long callNumbering(IDeferredMainInfo in)
{
String bizDt;
// 1. 기준일자를 가져옴.
bizDt = getStandardDate(in);
// 1.1 bizDt 가 null 일 있음. bizDt를 가져오는 다른 방안을 강구하거나
// 여기서처럼 return 0 하고 끝내던가
if ( !isValidBizDt(bizDt))
{
logger.error("Not valid bizDt : [{}]", bizDt);
return 0;
}
// 2. 현재 처리할 seq 데이터가 존재하는지 확인
int seqCount = getSeqData(in, bizDt);
// 3. Seq 테이블 초기 적재 및 전일자마감 여부 확인
if (seqCount == 0)
{
insertSeqInitialData(in, bizDt);
checkBeforeEndYn(in);
}
// 4. 현재 Numbering 할 정보 읽기
DfrdSeq01IO numberingInfo = getNumberingInfo(in, bizDt);
DfrdSeq01IO afterNumberingSeqInfo;
// 2017-09-05
// 4.1 갑작스런 중단에 대한 방어 로직
// 넘버링 하는 도중 갑작스럽게 중단되면 BXM_LOG_TRX 는 넘버링이 되있는데, BXM_DEFERRED_SEQ 는 반영이 안된 경우가 있음.
// BXM_LOG_TRX MAX_SEQ 를 가져와서 seqCount 랑 다르면 맞추기
int maxSeq = getMaxSeq(in, bizDt);
if (numberingInfo.getLastProcLogSeq().intValue() != maxSeq)
{
numberingInfo.setLastProcLogSeq(maxSeq);
numberingInfo.setProcExecCnt(maxSeq);
numberingInfo.setDomainId(in.getDomainId());
updateNumbering(numberingInfo);
}
// 5. 넘버링 실행
BigDecimal beforeProcExecCnt = numberingInfo.getProcExecCnt();
try
{
afterNumberingSeqInfo = executeNumbering(in, numberingInfo, bizDt);
}
catch (IllegalStateException e)
{
executeErrorProcess(in, bizDt);
throw new IllegalStateException("Numbering Error Update.");
}
// 6. BXM_DEFERRED_SEQ 최신화
BigDecimal procExecCnt = afterNumberingSeqInfo.getProcExecCnt();
if (procExecCnt.compareTo(beforeProcExecCnt) != 0)
updateSeq(afterNumberingSeqInfo);
// 7. LOG_SEQ 중복인 경우 에러 처리 (방어 로직 추가)
checkDuplicateLogSeq(in, bizDt);
// 8. 마지막 LogSeq 리턴8
return afterNumberingSeqInfo.getLastProcLogSeq().intValue();
}
@Override
public long checkIncompletionDataCnt(IDeferredMainInfo in)
{
// logger.debug("checkIncompletionDataCnt : [{}]", in);
return 0;
}
@Override
public long checkIncompletionNumberingCnt(IDeferredMainInfo in)
{
// logger.debug("checkIncompletionNumberingCnt : [{}]", in);
return 0;
}
private void updateNumbering(DfrdSeq01IO in)
{
if (dfrdSeqDBIO == null)
dfrdSeqDBIO = LApplicationContext.getBean(DfrdSeqDBIO.class);
dfrdSeqDBIO.updateLastProcLogSeq01(in);
}
private int getMaxSeq(IDeferredMainInfo in, String bizDt)
{
if (bxmLogTrxDBIO == null)
bxmLogTrxDBIO = LApplicationContext.getBean(BxmLogTrxDBIO.class);
String day = NumberingUtil.getBizDay(bizDt);
int maxSeq = bxmLogTrxDBIO.getMaxSeq01(day, bizDt, in.getDomainId());
return maxSeq;
}
private String getStandardDate(IDeferredMainInfo in)
{
if (dfrdStatusDBIO == null)
dfrdStatusDBIO = LApplicationContext.getBean(DfrdStatusDBIO.class);
DfrdStatus01IO dfrdStatus01IO = new DfrdStatus01IO();
dfrdStatus01IO.setDeferredId(in.getDeferredId());
dfrdStatus01IO.setDomainId(in.getDomainId());
String bizDt = dfrdStatusDBIO.selectDfrdStatus01(dfrdStatus01IO);
return bizDt;
}
private boolean isValidBizDt(String bizDt)
{
return !(StringUtils.isEmpty(bizDt)) && (bizDt.length() == 8);
}
private int getSeqData(IDeferredMainInfo in, String bizDt)
{
int seqCount;
if (dfrdSeqDBIO == null)
dfrdSeqDBIO = LApplicationContext.getBean(DfrdSeqDBIO.class);
DfrdSeq01IO dfrdSeq01IO = new DfrdSeq01IO();
dfrdSeq01IO.setDeferredId(in.getDeferredId());
dfrdSeq01IO.setBizDt(bizDt);
dfrdSeq01IO.setDomainId(in.getDomainId());
seqCount = dfrdSeqDBIO.selectDfrdSeqNotProcEnd01(dfrdSeq01IO);
return seqCount;
}
private void insertSeqInitialData(IDeferredMainInfo in, String bizDt)
{
DfrdSeq01IO dfrdSeqInitialData = new DfrdSeq01IO();
dfrdSeqInitialData.setDeferredId(in.getDeferredId());
dfrdSeqInitialData.setBizDt(bizDt);
dfrdSeqInitialData.setNodeNo(0);
dfrdSeqInitialData.setFirstProcStartDttm(NumberingUtil.getCurrentTime());
dfrdSeqInitialData.setLastProcLogSeq(0);
dfrdSeqInitialData.setProcExecCnt(0);
dfrdSeqInitialData.setProcEndYn("N");
dfrdSeqInitialData.setProcErrYn("N");
dfrdSeqInitialData.setDomainId(in.getDomainId());
try
{
dfrdSeqDBIO.insertDfrdSeq01(dfrdSeqInitialData);
}
catch (DasDuplicateKeyException e)
{
logger.error("deferredId [{}], baseDt [{}] is already exist. ", in.getDeferredId(), bizDt);
}
}
private void checkBeforeEndYn(IDeferredMainInfo in)
{
DfrdWork01IO beforeDayDfrdWork01IO = new DfrdWork01IO();
beforeDayDfrdWork01IO.setBizDt(NumberingUtil.getBeforeDay());
beforeDayDfrdWork01IO.setDeferredId(in.getDeferredId());
beforeDayDfrdWork01IO.setDomainId(in.getDomainId());
if (dfrdWorkDBIO == null)
dfrdWorkDBIO = LApplicationContext.getBean(DfrdWorkDBIO.class);
int dfrdEndWorkCount = dfrdWorkDBIO.selectDfrdWorkAboutWorkEnd01(beforeDayDfrdWork01IO);
if (dfrdEndWorkCount != 0)
{
DfrdSeq01IO updateDfrdSeqEndYn = new DfrdSeq01IO();
updateDfrdSeqEndYn.setBizDt(NumberingUtil.getBeforeDay());
updateDfrdSeqEndYn.setDeferredId(in.getDeferredId());
updateDfrdSeqEndYn.setProcEndYn("Y");
updateDfrdSeqEndYn.setLastProcEndDttm(NumberingUtil.getCurrentTime());
updateDfrdSeqEndYn.setDomainId(in.getDomainId());
if (dfrdSeqDBIO == null)
dfrdSeqDBIO = LApplicationContext.getBean(DfrdSeqDBIO.class);
dfrdSeqDBIO.updateDfrdSeqEndYn01(updateDfrdSeqEndYn);
}
}
private DfrdSeq01IO getNumberingInfo(IDeferredMainInfo in, String bizDt)
{
if (dfrdSeqDBIO == null)
dfrdSeqDBIO = LApplicationContext.getBean(DfrdSeqDBIO.class);
DfrdSeq01IO selectDfrdSeq01IO = new DfrdSeq01IO();
selectDfrdSeq01IO.setDeferredId(in.getDeferredId());
selectDfrdSeq01IO.setBizDt(bizDt);
selectDfrdSeq01IO.setDomainId(in.getDomainId());
DfrdSeq01IO out = dfrdSeqDBIO.selectDfrdSeq01(selectDfrdSeq01IO);
return out;
}
private DfrdSeq01IO executeNumbering(IDeferredMainInfo deferredMainInfo, DfrdSeq01IO in, String bizDt)
{
DfrdSeq01IO out = new DfrdSeq01IO();
out.setCurrProcStartDttm(NumberingUtil.getCurrentTime());
String day = NumberingUtil.getBizDay(bizDt);
BigDecimal startSeqNo, endSeqNo, maxSeqNo;
int processedNumberingCount = 0;
int sqlResult;
startSeqNo = in.getLastProcLogSeq();
maxSeqNo = in.getLastProcLogSeq();
if (bxmLogTrxDBIO == null)
bxmLogTrxDBIO = LApplicationContext.getBean(BxmLogTrxDBIO.class);
List<BxmLogTrx01IO> list = bxmLogTrxDBIO.selectListLogTrx01(day, bizDt, deferredMainInfo.getDomainId());
for (BxmLogTrx01IO bxmLogTrx01IO : list)
{
maxSeqNo = maxSeqNo.add(BigDecimal.ONE);
bxmLogTrx01IO.setLogSeq(maxSeqNo);
bxmLogTrx01IO.setDay(day);
bxmLogTrx01IO.setDomainId(deferredMainInfo.getDomainId());
sqlResult = bxmLogTrxDBIO.updateDfrdInput01(bxmLogTrx01IO);
if(sqlResult == 0)
{
logger.error("deferredId : [{}] Numbering Update Error. guid : [{}], curSeq : [{}]"
, new Object[]{in.getDeferredId(), bxmLogTrx01IO.getGuid(), maxSeqNo});
throw new IllegalStateException("Dfrd AcctgLog Numbering Update Error.");
}
else
{
processedNumberingCount += 1;
}
}
endSeqNo = maxSeqNo;
logger.debug("deferredId : [{}] Dfrd AcctgLog Numering Update startSeq [{}] ~ endSeq[{}]"
, new Object[]{in.getDeferredId(), startSeqNo, endSeqNo});
out.setDeferredId(in.getDeferredId());
out.setBizDt(bizDt);
out.setLastProcLogSeq(maxSeqNo);
out.setProcExecCnt(in.getProcExecCnt().intValue()
+ processedNumberingCount);
out.setNodeNo(in.getNodeNo());
out.setDomainId(deferredMainInfo.getDomainId());
return out;
}
private void executeErrorProcess(IDeferredMainInfo in, String bizDt)
{
DfrdSeq01IO dfrdSeq01IO = new DfrdSeq01IO();
dfrdSeq01IO.setDeferredId(in.getDeferredId());
dfrdSeq01IO.setCurrProcStartDttm(NumberingUtil.getCurrentTime());
dfrdSeq01IO.setBizDt(bizDt);
dfrdSeq01IO.setDomainId(in.getDomainId());
if (dfrdSeqDBIO == null)
dfrdSeqDBIO = LApplicationContext.getBean(DfrdSeqDBIO.class);
dfrdSeqDBIO.updateDfrdSeqErr01(dfrdSeq01IO);
}
private void updateSeq(DfrdSeq01IO in)
{
if (dfrdSeqDBIO == null)
dfrdSeqDBIO = LApplicationContext.getBean(DfrdSeqDBIO.class);
dfrdSeqDBIO.updateDfrdSeqLastest01(in);
}
private void checkDuplicateLogSeq(IDeferredMainInfo deferredMainInfo, String bizDt)
{
if (bxmLogTrxDBIO == null)
bxmLogTrxDBIO = LApplicationContext.getBean(BxmLogTrxDBIO.class);
String day = NumberingUtil.getBizDay(bizDt);
List<Integer> result = bxmLogTrxDBIO.selectListLogTrx03(day, deferredMainInfo.getDomainId());
if (result.size() != 0)
{
logger.error("LOG_SEQ not duplicate");
for (Integer i : result)
{
logger.error("duplicate log_seq : [{}]", i);
}
throw new IllegalStateException("LOG_SEQ not duplicate");
}
}