아래는 주어진 사양을 바탕으로 설계된 Monitoring 수행 Java 배치 프로그램의 기본 구조와 함께, 관련 MariaDB 테이블 생성 SQL을 제공합니다. 이 프로그램은 모니터링 항목에 따라 주기적으로 SQL을 실행하고, 그 결과를 임계치 기준으로 평가하여 결과를 기록합니다.


🔧 1. MariaDB 테이블 생성 SQL

-- 모니터링 항목 테이블
CREATE TABLE monitoring_item (
    item_id            BIGINT AUTO_INCREMENT PRIMARY KEY,
    system             VARCHAR(100),
    module             VARCHAR(100),
    testcase_id        VARCHAR(100),
    testcase_name      VARCHAR(200),
    activity_no        VARCHAR(100),
    monitoring_name    VARCHAR(200),
    description        TEXT,
    action_guide       TEXT,
    use_yn             CHAR(1) DEFAULT 'Y',
    monitoring_cycle   VARCHAR(10), -- DAILY, WEEKLY, MONTHLY
    cycle_week         VARCHAR(10), -- 월: MON, 화: TUE ...
    cycle_day          INT, -- 1~31 (Monthly)
    start_time         VARCHAR(4), -- HHMM 형식
    time_interval      INT, -- 분 단위
    monitoring_from    DATE,
    monitoring_to      DATE,
    exclude_from       DATE,
    exclude_to         DATE,
    sql_text           TEXT,
    green_operator     VARCHAR(2), -- <, <=, =, >=, >
    green_value        DOUBLE,
    red_operator       VARCHAR(2),
    red_value          DOUBLE,
    created_at         TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 모니터링 실행 결과 테이블
CREATE TABLE monitoring_result (
    result_id          BIGINT AUTO_INCREMENT PRIMARY KEY,
    item_id            BIGINT,
    run_date           DATE,
    run_time           TIME,
    run_rank           INT,
    status             VARCHAR(20), -- 대기, 실행중, 성공, 실패
    result_value       DOUBLE,
    result_level       VARCHAR(10), -- GREEN, RED, NONE
    result_message     TEXT,
    created_at         TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (item_id) REFERENCES monitoring_item(item_id)
);

🚀 2. Java 배치 프로그램 개요

기술 스택

  • OpenJDK 11
  • Spring Boot (or Spring Batch if 원하는 경우)
  • iBatis 또는 MyBatis
  • JDBC

🔁 JobSchedulerService.java

@Service
public class JobSchedulerService {
    @Autowired
    private MonitoringRepository monitoringRepository;

    public void runBatchJob() {
        LocalDate today = LocalDate.now();
        LocalTime now = LocalTime.now();
        List<MonitoringItem> items = monitoringRepository.findExecutableItems(today, now);

        for (MonitoringItem item : items) {
            if (!isInExcludePeriod(item)) {
                MonitoringResult result = executeMonitoring(item, now);
                monitoringRepository.saveResult(result);
            }
        }
    }

    private boolean isInExcludePeriod(MonitoringItem item) {
        LocalDate now = LocalDate.now();
        return (item.getExcludeFrom() != null && item.getExcludeTo() != null)
            && !now.isBefore(item.getExcludeFrom()) && !now.isAfter(item.getExcludeTo());
    }

    private MonitoringResult executeMonitoring(MonitoringItem item, LocalTime now) {
        MonitoringResult result = new MonitoringResult();
        result.setItemId(item.getId());
        result.setRunDate(LocalDate.now());
        result.setRunTime(now);
        result.setStatus("실행중");

        try (Connection conn = dataSource.getConnection();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(item.getSqlText())) {

            double value = 0.0;
            if (rs.next()) {
                value = rs.getDouble(1);
            }

            result.setResultValue(value);
            result.setResultLevel(evaluateLevel(value, item));
            result.setStatus("성공");
            result.setResultMessage("정상 수행");

        } catch (Exception e) {
            result.setStatus("실패");
            result.setResultMessage(e.getMessage());
        }

        return result;
    }

    private String evaluateLevel(double value, MonitoringItem item) {
        if (compare(value, item.getRedOperator(), item.getRedValue())) {
            return "RED";
        } else if (compare(value, item.getGreenOperator(), item.getGreenValue())) {
            return "GREEN";
        }
        return "NONE";
    }

    private boolean compare(double actual, String operator, double threshold) {
        return switch (operator) {
            case ">" -> actual > threshold;
            case ">=" -> actual >= threshold;
            case "<" -> actual < threshold;
            case "<=" -> actual <= threshold;
            case "=" -> actual == threshold;
            default -> false;
        };
    }
}

🕐 실행 조건 쿼리 (MyBatis XML 또는 Mapper)

<!-- 실행 대상 항목 조회 -->
<select id="findExecutableItems" resultType="MonitoringItem">
SELECT *
FROM monitoring_item
WHERE use_yn = 'Y'
  AND CURDATE() BETWEEN monitoring_from AND monitoring_to
  AND (monitoring_cycle = 'DAILY'
       OR (monitoring_cycle = 'WEEKLY' AND cycle_week = #{dayOfWeek})
       OR (monitoring_cycle = 'MONTHLY' AND cycle_day = #{dayOfMonth}))
  AND #{nowTime} >= start_time
  AND MOD(TIMESTAMPDIFF(MINUTE, STR_TO_DATE(start_time, '%H%i'), #{nowTime}), time_interval) = 0
</select>

🗓️ 3. 배치 스케줄링 (Spring 기반)

@Component
public class BatchScheduler {

    @Autowired
    private JobSchedulerService jobSchedulerService;

    // 매 1분마다 실행
    @Scheduled(cron = "0 */1 * * * *")
    public void scheduleBatch() {
        jobSchedulerService.runBatchJob();
    }
}

✅ 요약

구성 요소내용
테이블monitoring_item, monitoring_result
주기DAILY / WEEKLY / MONTHLY (시간 및 분 기준 제어)
제외 기간exclude_from, exclude_to 반영
결과 평가Green / Red 기준값 비교 연산 지원
배치 실행매 1분마다 수행, 자정에는 monitoring_item 기준으로 판단

필요 시 다음 항목도 확장 가능합니다:

  • Slack 또는 이메일 알림 연동
  • 모니터링 실패 자동 재시도
  • 실행 이력 별 통계

필요하다면 이 구조에 맞는 React 관리자 화면 예시 UI, 또는 iBatis Mapper XML 파일도 도와드릴 수 있습니다. 추가 요청 주시면 이어서 작성해드릴게요!

tag: none

댓글추가