wing-ops/backend/src/monitor/monitorService.ts
2026-03-25 15:35:43 +09:00

122 lines
4.1 KiB
TypeScript

export interface NumericalDataStatus {
modelName: string;
jobName: string;
lastStatus: 'COMPLETED' | 'FAILED' | 'STARTED' | 'UNKNOWN';
lastDataDate: string | null; // 데이터 기준일 (YYYY-MM-DD)
lastDownloadedAt: string | null; // 마지막 실행 완료 시각 (ISO)
nextScheduledAt: string | null; // Quartz 다음 예정 시각 (ISO)
durationSec: number | null; // 소요 시간 (초)
consecutiveFailures: number; // 연속 실패 횟수
}
// ============================================================
// Mock 데이터 (Spring Batch/Quartz DB 연동 전)
// DB 연동 준비 완료 후 getMockNumericalDataStatus → getActualNumericalDataStatus 교체
// ============================================================
const MOCK_DATA: NumericalDataStatus[] = [
{
modelName: 'HYCOM',
jobName: 'downloadHycomJob',
lastStatus: 'COMPLETED',
lastDataDate: '2026-03-25',
lastDownloadedAt: '2026-03-25T06:12:34',
nextScheduledAt: '2026-03-25T12:00:00',
durationSec: 342,
consecutiveFailures: 0,
},
{
modelName: 'GFS',
jobName: 'downloadGfsJob',
lastStatus: 'COMPLETED',
lastDataDate: '2026-03-25',
lastDownloadedAt: '2026-03-25T06:48:11',
nextScheduledAt: '2026-03-25T12:00:00',
durationSec: 518,
consecutiveFailures: 0,
},
{
modelName: 'WW3',
jobName: 'downloadWw3Job',
lastStatus: 'FAILED',
lastDataDate: '2026-03-24',
lastDownloadedAt: '2026-03-25T07:03:55',
nextScheduledAt: '2026-03-25T13:00:00',
durationSec: null,
consecutiveFailures: 2,
},
{
modelName: 'KOAST POS_WIND',
jobName: 'downloadKoastWindJob',
lastStatus: 'COMPLETED',
lastDataDate: '2026-03-25',
lastDownloadedAt: '2026-03-25T07:21:05',
nextScheduledAt: '2026-03-25T13:00:00',
durationSec: 127,
consecutiveFailures: 0,
},
{
modelName: 'KOAST POS_HYDR',
jobName: 'downloadKoastHydrJob',
lastStatus: 'COMPLETED',
lastDataDate: '2026-03-25',
lastDownloadedAt: '2026-03-25T07:35:48',
nextScheduledAt: '2026-03-25T13:00:00',
durationSec: 183,
consecutiveFailures: 0,
},
{
modelName: 'KOAST POS_WAVE',
jobName: 'downloadKoastWaveJob',
lastStatus: 'COMPLETED',
lastDataDate: '2026-03-25',
lastDownloadedAt: '2026-03-25T07:52:19',
nextScheduledAt: '2026-03-25T13:00:00',
durationSec: 156,
consecutiveFailures: 0,
},
];
export async function getNumericalDataStatus(): Promise<NumericalDataStatus[]> {
// TODO: Spring Batch + Quartz DB 테이블 생성 후 아래 실제 쿼리로 교체
//
// import { wingDb } from '../db/wingDb.js'
//
// -- 각 Job의 최신 실행 결과 조회 (BATCH_JOB_EXECUTION)
// SELECT
// ji.JOB_NAME,
// je.START_TIME, je.END_TIME,
// je.STATUS, je.EXIT_CODE, je.EXIT_MESSAGE,
// jep.STRING_VAL AS data_date,
// EXTRACT(EPOCH FROM (je.END_TIME - je.START_TIME))::INT AS duration_sec
// FROM BATCH_JOB_EXECUTION je
// JOIN BATCH_JOB_INSTANCE ji ON je.JOB_INSTANCE_ID = ji.JOB_INSTANCE_ID
// LEFT JOIN BATCH_JOB_EXECUTION_PARAMS jep
// ON je.JOB_EXECUTION_ID = jep.JOB_EXECUTION_ID
// AND jep.KEY_NAME = 'data_date'
// WHERE je.JOB_EXECUTION_ID IN (
// SELECT MAX(je2.JOB_EXECUTION_ID)
// FROM BATCH_JOB_EXECUTION je2
// GROUP BY je2.JOB_INSTANCE_ID
// )
// ORDER BY je.START_TIME DESC;
//
// -- Quartz 다음 실행 예정 시각 (NEXT_FIRE_TIME은 epoch milliseconds)
// SELECT JOB_NAME, to_timestamp(NEXT_FIRE_TIME / 1000) AS next_fire_time
// FROM QRTZ_TRIGGERS;
//
// -- 연속 실패 횟수 집계 (최근 실행부터 COMPLETED 전까지 카운트)
// SELECT ji.JOB_NAME, COUNT(*) AS consecutive_failures
// FROM BATCH_JOB_EXECUTION je
// JOIN BATCH_JOB_INSTANCE ji ON je.JOB_INSTANCE_ID = ji.JOB_INSTANCE_ID
// WHERE je.STATUS = 'FAILED'
// AND je.JOB_EXECUTION_ID > (
// SELECT COALESCE(MAX(je2.JOB_EXECUTION_ID), 0)
// FROM BATCH_JOB_EXECUTION je2
// WHERE je2.JOB_INSTANCE_ID = je.JOB_INSTANCE_ID
// AND je2.STATUS = 'COMPLETED'
// )
// GROUP BY ji.JOB_NAME;
return MOCK_DATA;
}