배치그룹 제어

배치가 실행 되어 있을 때 현재 실행되고 있는 배치가 속한 그룹 정보를 확인하여 배치에 대한 실행 제어 커스터마이징을 할 수 있다.

1. 배치 그룹 테이블

다음은 배치 그룹 테이블에 대한 설명이다.

1.1. 배치작업그룹(BXM_JOB_GRP)

배치작업그룹
컬럼ID 컬럼명 설명

DOMAIN_ID

도메인ID

도메인ID

JOB_GRP_ID

배치작업그룹ID

배치 그룹 제어 처리 할 ID

JOB_GRP_NM

배치작업그룹명

배치작업그룹ID의 한글명

USE_YN

사용여부

실행되고 있는 배치의 그룹을 제어 할 것인지에 대한
Flag 값이다.

NODE_MAX_EXEC_VALID_YN

NODE 최대 실행 검증 여부

노드별 실행 제어를 할
것인지에 대한 Flag 값이다.

NODE_MAX_EXEC_CNT

NODE 최대 실행 수

배치가 실행하는 노드에서 그룹에
속한 배치들이 최대로 실행 할 수 있는 개수를 의미한다.

SYS_MAX_EXEC_VALID_YN

시스템 최대 실행 검증 여부

배치가 수행하고 있는
시스템에서 실행 제어를 할 것인지에 대한 Flag 값이다.

SYS_MAX_EXEC_CNT

시스템 최대 실행 수

배치가 실행하는 시스템에서
그룹에 속한 배치들이 최대로 실행 할 수 있는 개수를 의미한다.

1.2. 배치작업그룹관계(BXM_JOB_GRP_RLTON)

배치작업그룹관계
컬럼ID 컬럼명 설명

DOMAIN_ID

도메인ID

도메인ID

JOB_GRP_ID

배치작업그룹ID

배치 그룹 제어 처리 할 ID

JOB_ID

배치작업ID

배치작업그룹에 정의된 배치작업ID

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 한다.

loadBatchGroupInfo() Method 설명

속성

설명

파라미터

String jobId

배치 그룹 정보를 조회하기 위한 배치 작업 Id.(Spring에서는 Job Name)

DataSource dataSource

배치 그룹 정보를 조회 처리하기 위한 DataSource.

반환값

Map<String, BatchJobGroupInfo>

배치 그룹 정보를 조회한 결과

2.1.2. batchGroupCheck() Method

실행되고 있는 배치작업 ID로 배치 그룹정보를 조회한 결과를 바탕으로 배치에 대한 실행 가능 여부를 확인하여 실행 제어 처리를 한다.

배치 실행에 대한 제어는 현재 배치가 실행되고 있는 노드(Node)와 배치 시스템 전체에 대하여 그룹별 배치 실행 개수를 확인하여 제어 처리를 한다.

batchGroupCheck() Method 설명

속성

설명

파라미터

String jobId

배치 실행 시 입력한 배치작업 ID(Spring에서는 Job Name).

DataSource dataSource

배치 그룹 정보를 Check 하기 위한 DataSource

String jobGrpId

배치 그룹에 속한 배치작업 정보를 가져오기 위한 그룹ID

BatchJobGroupInfo

batchGroupInfo

배치 그룹에 대한 정보.(제어, 최대 실행 개수 등.)

반환값

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;
    }

    ......

3. 적용 방법

만일 배치그룹제어와 관련하여 커스터마이징을 모듈을 개발하였다면 해당 모듈을 배치 Instance Configuration 파일(예:bxm-batch.xml)의 batch-context에 적용할 수 있다.

    ...
    <batch-context>
        <batch-batchgroup classname="bxm.batch.dft.control.DefaultBatchGroupCheckProcessor"/>
    </batch-context>
    ...

Copyright© Bankwareglobal All Rights Reserved.