배치그룹 제어
배치가 실행 되어 있을 때 현재 실행되고 있는 배치가 속한 그룹 정보를 확인하여 배치에 대한 실행 제어 커스터마이징을 할 수 있다.
1. 배치 그룹 테이블
다음은 배치 그룹 테이블에 대한 설명이다.
1.1. 배치작업그룹(BXM_JOB_GRP)
컬럼ID | 컬럼명 | 설명 |
---|---|---|
DOMAIN_ID |
도메인ID |
도메인ID |
JOB_GRP_ID |
배치작업그룹ID |
배치 그룹 제어 처리 할 ID |
JOB_GRP_NM |
배치작업그룹명 |
배치작업그룹ID의 한글명 |
USE_YN |
사용여부 |
실행되고 있는 배치의 그룹을 제어 할 것인지에 대한 |
NODE_MAX_EXEC_VALID_YN |
NODE 최대 실행 검증 여부 |
노드별 실행 제어를 할 |
NODE_MAX_EXEC_CNT |
NODE 최대 실행 수 |
배치가 실행하는 노드에서 그룹에 |
SYS_MAX_EXEC_VALID_YN |
시스템 최대 실행 검증 여부 |
배치가 수행하고 있는 |
SYS_MAX_EXEC_CNT |
시스템 최대 실행 수 |
배치가 실행하는 시스템에서 |
2. 배치 그룹 제어 커스터마이징
배치가 실행 되었을때 실행한 배치에 대하여 그룹에 대한 제어를 하기 위하여 다음과 같은 Interface를 제공하고 있다.
2.1. BatchGroupCheckProcessor Interface
배치 그룹를 체크하기 위한 Interface로서, 배치작업그룹(BXM_JOB_GRP)테이블을 Load하여, 현재 배치가 실행되고 있는 노드, 시스템별 최대 실행 수 에 대하여 제어 처리를 할 수 있다.
최대 수 실행 수 제어 외에 그룹 별로 제어를 하고 싶다면 배치작업그룹 테이블을 커스터마이징하여 처리하면 된다.
BatchGroupCheckProcessor Interface의 구현 Method는 다음과 같다.
public Map<String, BatchJobGroupInfo> loadBatchGroupInfo(String jobId, DataSource dataSource) throws Exception;
public boolean batchGroupCheck(String jobId, DataSource dataSource, String jobGrpId, BatchJobGroupInfo batchGroupInfo) throws Exception;
2.1.1. loadBatchGroupInfo() Method
실행되고 있는 배치가 포함되어있는 배치 그룹 정보를 Load 한다.
속성 |
설명 |
|
파라미터 |
String jobId |
배치 그룹 정보를 조회하기 위한 배치 작업 Id.(Spring에서는 Job Name) |
DataSource dataSource |
배치 그룹 정보를 조회 처리하기 위한 DataSource. |
|
반환값 |
Map<String, BatchJobGroupInfo> |
배치 그룹 정보를 조회한 결과 |
2.1.2. batchGroupCheck() Method
실행되고 있는 배치작업 ID로 배치 그룹정보를 조회한 결과를 바탕으로 배치에 대한 실행 가능 여부를 확인하여 실행 제어 처리를 한다.
배치 실행에 대한 제어는 현재 배치가 실행되고 있는 노드(Node)와 배치 시스템 전체에 대하여 그룹별 배치 실행 개수를 확인하여 제어 처리를 한다.
속성 |
설명 |
|
파라미터 |
String jobId |
배치 실행 시 입력한 배치작업 ID(Spring에서는 Job Name). |
DataSource dataSource |
배치 그룹 정보를 Check 하기 위한 DataSource |
|
String jobGrpId |
배치 그룹에 속한 배치작업 정보를 가져오기 위한 그룹ID |
|
BatchJobGroupInfo |
배치 그룹에 대한 정보.(제어, 최대 실행 개수 등.) |
|
반환값 |
boolean |
배치 그룹 체크 결과 |
참고로 배치의 Node, System 정보 체크는 BXM_RUNTIME_INSTANCE 테이블에 등록되어 있는 Instance 정보를 조회하여 체크를 한다.
-
참고 설명 : 배치가 실행이 되면 배치의 Instance 정보(JMX 연결정보 포함)가 BXM_RUNTIME_INSTANCE 테이블에 등록이 된다.
2.2. Sample Source
자세한 Source Sample은 bxm-batch-default-extension 프로젝트의 DefaultBatchGroupCheckProcessor.java 를 참고한다.
package bxm.batch.dft.control;
......
public class DefaultBatchGroupCheckProcessor implements BatchGroupCheckProcessor{
private static final Logger logger = LoggerFactory.getLogger(DefaultBatchGroupCheckProcessor.class);
@Override
public Map<String, BatchJobGroupInfo> loadBatchGroupInfo(String jobId, DataSource dataSource) throws Exception
{
Map<String, BatchJobGroupInfo> groupInfos = null;
try
{
BatchGroupMapper mapper = JdbcOperatorUtils.getMapper(BatchGroupMapper.class);
List<BatchGroupDto> batchGroupDtos = mapper.selectBatchGroup(
BatchApplicationContext.getDomainId(), jobId, BatchCommYN.Y.name());
if(batchGroupDtos != null && !batchGroupDtos.isEmpty())
{
for(BatchGroupDto batchGroupDto : batchGroupDtos)
{
if(groupInfos == null) groupInfos = new HashMap<String, BatchJobGroupInfo>();
BatchJobGroupInfo batchGroupInfo = new BatchJobGroupInfo();
batchGroupInfo.setJobGrpId(batchGroupDto.getJobGrpId());
batchGroupInfo.setJobGrpNm(batchGroupDto.getJobGrpNm());
batchGroupInfo.setUseYn(true);
batchGroupInfo.setNodeMaxExecValidYn(BatchCommYN.valueOf(batchGroupDto.getNodeMaxExecValidYn()).getBoolean());
batchGroupInfo.setNodeMaxExecCnt(batchGroupDto.getNodeMaxExecCnt());
batchGroupInfo.setSysMaxExecValidYn(BatchCommYN.valueOf(batchGroupDto.getSysMaxExecValidYn()).getBoolean());
batchGroupInfo.setSysMaxExecCnt(batchGroupDto.getSysMaxExecCnt());
logger.debug("Batch Job Group : {}", batchGroupInfo.getJobGrpId());
groupInfos.put(batchGroupInfo.getJobGrpId(), batchGroupInfo);
}
}
}
catch (Exception e)
{
logger.error(e.getMessage(), e);
throw e;
}
return groupInfos;
}
@Override
public boolean batchGroupCheck(String jobId, DataSource dataSource, String jobGrpId, BatchJobGroupInfo batchGroupInfo) throws Exception {
if(!batchGroupInfo.isUseYn())
{
logger.error("BXM_JOB_GRP USE_YN column value is false.");
return false;
}
// Node
if(batchGroupInfo.isNodeMaxExecValidYn())
{
logger.info("Batch Job Group Node check. [{}]/[{}]", jobGrpId, batchGroupInfo.getNodeMaxExecCnt());
boolean resultVal = jobGroupCountCheck(batchGroupInfo.getJobGrpId()
, dataSource
, true
, false
, batchGroupInfo.getNodeMaxExecCnt());
if(!resultVal)
{
String errMsg = String.format("The maximum job execution count has been exceeded. "
+ "Group Id : [%s], Maximum number of running jobs in the node : [%d]", jobGrpId, batchGroupInfo.getNodeMaxExecCnt());
logger.error(errMsg);
throw new IllegalStateException(errMsg);
//return resultVal;
}
}
// System
if(batchGroupInfo.isSysMaxExecValidYn())
{
logger.info("Batch Job Group System check. [{}]/[{}]", jobGrpId, batchGroupInfo.getSysMaxExecCnt());
boolean resultVal = jobGroupCountCheck(batchGroupInfo.getJobGrpId()
, dataSource
, false
, true
, batchGroupInfo.getSysMaxExecCnt());
if(!resultVal)
{
String errMsg = String.format("The maximum job execution count has been exceeded. "
+ "Group Id : [{}], Maximum number of running jobs in the system : [{}]", jobGrpId, batchGroupInfo.getSysMaxExecCnt());
logger.error(errMsg);
throw new IllegalStateException(errMsg);
// return resultVal;
}
}
return true;
}
private boolean jobGroupCountCheck(String jobGrpId, DataSource dataSource, boolean isNode, boolean isSys, int execCnt) throws Exception
{
boolean checkVal = false;
try
{
int count = 0;
BatchGroupMapper mapper = JdbcOperatorUtils.getMapper(BatchGroupMapper.class);
if(isNode)
{
count = mapper.selectBatchGroupCountByNode(BatchApplicationContext.getDomainId()
, jobGrpId, BatchCommonUtils.getPidNHostName(), getHostName());
}
else if(isSys)
{
count = mapper.selectBatchGroupCountBySystem(BatchApplicationContext.getDomainId()
, jobGrpId, BatchCommonUtils.getPidNHostName());
}
else
{
logger.info("Batch Job Group use_yn column is [N].");
return true;
}
// 개별 체크
int reCount = 0;
if(count >= execCnt)
{
List<BatchGroupDto> batchGroupDtos = null;
if(isNode)
{
batchGroupDtos = mapper.selectBatchGroupRuntimeInfoByNode(BatchApplicationContext.getDomainId()
, jobGrpId, BatchCommonUtils.getPidNHostName(), getHostName());
}
else if(isSys)
{
batchGroupDtos = mapper.selectBatchGroupRuntimeInfoBySystem(BatchApplicationContext.getDomainId()
, jobGrpId, BatchCommonUtils.getPidNHostName());
}
if(batchGroupDtos != null && !batchGroupDtos.isEmpty())
{
for(BatchGroupDto batchGroupDto : batchGroupDtos)
{
String url = batchGroupDto.getMngSvcUrl();
String pid = batchGroupDto.getBxmInstancePid();
boolean isSameNode = StringUtils.hasText(pid) && pid.endsWith(getHostName()) ? true : false;
if(isSameNode)
{
if(sendCheck(url, dataSource))
{
reCount++;
}
}
else
{
reCount++;
}
}
}
if(reCount >= execCnt)
{
checkVal = false;
}
else
{
checkVal = true;
}
}
else
{
checkVal = true;
}
}
catch (Exception e)
{
logger.error(e.getMessage(), e);
throw e;
}
return checkVal;
}
......