release: 2026-03-25 (8건 커밋) #104
@ -0,0 +1,37 @@
|
||||
package com.snp.batch.global.cleanup;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 배치 로그 정리 설정
|
||||
*
|
||||
* 로그 종류별 보존 기간(일) 설정
|
||||
*
|
||||
* 설정 예시:
|
||||
* app.batch.log-cleanup:
|
||||
* api-log-retention-days: 30
|
||||
* batch-meta-retention-days: 90
|
||||
* failed-record-retention-days: 90
|
||||
* recollection-history-retention-days: 90
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "app.batch.log-cleanup")
|
||||
public class LogCleanupConfig {
|
||||
|
||||
/** batch_api_log 보존 기간 (일) */
|
||||
private int apiLogRetentionDays = 30;
|
||||
|
||||
/** Spring Batch 메타 테이블 보존 기간 (일) */
|
||||
private int batchMetaRetentionDays = 90;
|
||||
|
||||
/** batch_failed_record (RESOLVED) 보존 기간 (일) */
|
||||
private int failedRecordRetentionDays = 90;
|
||||
|
||||
/** batch_recollection_history 보존 기간 (일) */
|
||||
private int recollectionHistoryRetentionDays = 90;
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.snp.batch.global.cleanup;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobExecutionListener;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.job.builder.JobBuilder;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.step.builder.StepBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
* 배치 로그 정리 Job Config
|
||||
*
|
||||
* 스케줄: 매일 02:00 (0 0 2 * * ?)
|
||||
*
|
||||
* 동작:
|
||||
* - 보존 기간이 지난 배치 로그 데이터를 삭제
|
||||
* - batch_api_log (30일), Spring Batch 메타 (90일),
|
||||
* batch_failed_record/RESOLVED (90일), batch_recollection_history (90일)
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class LogCleanupJobConfig {
|
||||
|
||||
private final JobRepository jobRepository;
|
||||
private final PlatformTransactionManager transactionManager;
|
||||
private final LogCleanupTasklet logCleanupTasklet;
|
||||
|
||||
public LogCleanupJobConfig(
|
||||
JobRepository jobRepository,
|
||||
PlatformTransactionManager transactionManager,
|
||||
LogCleanupTasklet logCleanupTasklet) {
|
||||
this.jobRepository = jobRepository;
|
||||
this.transactionManager = transactionManager;
|
||||
this.logCleanupTasklet = logCleanupTasklet;
|
||||
}
|
||||
|
||||
@Bean(name = "logCleanupStep")
|
||||
public Step logCleanupStep() {
|
||||
return new StepBuilder("logCleanupStep", jobRepository)
|
||||
.tasklet(logCleanupTasklet, transactionManager)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean(name = "LogCleanupJob")
|
||||
public Job logCleanupJob() {
|
||||
log.info("Job 생성: LogCleanupJob");
|
||||
|
||||
return new JobBuilder("LogCleanupJob", jobRepository)
|
||||
.listener(new JobExecutionListener() {
|
||||
@Override
|
||||
public void beforeJob(JobExecution jobExecution) {
|
||||
log.info("[LogCleanupJob] 배치 로그 정리 Job 시작");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterJob(JobExecution jobExecution) {
|
||||
log.info("[LogCleanupJob] 배치 로그 정리 Job 완료 - 상태: {}",
|
||||
jobExecution.getStatus());
|
||||
}
|
||||
})
|
||||
.start(logCleanupStep())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,148 @@
|
||||
package com.snp.batch.global.cleanup;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class LogCleanupTasklet implements Tasklet {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final LogCleanupConfig config;
|
||||
|
||||
@Value("${app.batch.target-schema.name}")
|
||||
private String schema;
|
||||
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||
log.info("========================================");
|
||||
log.info("배치 로그 정리 Job 시작");
|
||||
log.info("========================================");
|
||||
|
||||
int totalDeleted = 0;
|
||||
|
||||
// 1. batch_api_log 정리
|
||||
totalDeleted += cleanupApiLog();
|
||||
|
||||
// 2. Spring Batch 메타 테이블 정리 (FK 순서)
|
||||
totalDeleted += cleanupBatchMeta();
|
||||
|
||||
// 3. batch_failed_record 정리 (RESOLVED만)
|
||||
totalDeleted += cleanupFailedRecord();
|
||||
|
||||
// 4. batch_recollection_history 정리
|
||||
totalDeleted += cleanupRecollectionHistory();
|
||||
|
||||
log.info("========================================");
|
||||
log.info("배치 로그 정리 Job 완료 - 총 삭제: {} 건", totalDeleted);
|
||||
log.info("========================================");
|
||||
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
|
||||
private int cleanupApiLog() {
|
||||
int days = config.getApiLogRetentionDays();
|
||||
String sql = String.format(
|
||||
"DELETE FROM %s.batch_api_log WHERE created_at < NOW() - INTERVAL '%d days'",
|
||||
schema, days);
|
||||
int deleted = jdbcTemplate.update(sql);
|
||||
log.info("[batch_api_log] 보존기간: {}일, 삭제: {}건", days, deleted);
|
||||
return deleted;
|
||||
}
|
||||
|
||||
private int cleanupBatchMeta() {
|
||||
int days = config.getBatchMetaRetentionDays();
|
||||
int totalDeleted = 0;
|
||||
|
||||
// FK 의존 순서: step_execution_context → step_execution → job_execution_context → job_execution_params → job_execution → job_instance(orphan)
|
||||
|
||||
// 1. batch_step_execution_context
|
||||
String sql1 = String.format(
|
||||
"DELETE FROM %s.batch_step_execution_context WHERE step_execution_id IN (" +
|
||||
"SELECT se.step_execution_id FROM %s.batch_step_execution se " +
|
||||
"JOIN %s.batch_job_execution je ON se.job_execution_id = je.job_execution_id " +
|
||||
"WHERE je.create_time < NOW() - INTERVAL '%d days')",
|
||||
schema, schema, schema, days);
|
||||
int deleted = jdbcTemplate.update(sql1);
|
||||
totalDeleted += deleted;
|
||||
log.info("[batch_step_execution_context] 삭제: {}건", deleted);
|
||||
|
||||
// 2. batch_step_execution
|
||||
String sql2 = String.format(
|
||||
"DELETE FROM %s.batch_step_execution WHERE job_execution_id IN (" +
|
||||
"SELECT job_execution_id FROM %s.batch_job_execution " +
|
||||
"WHERE create_time < NOW() - INTERVAL '%d days')",
|
||||
schema, schema, days);
|
||||
deleted = jdbcTemplate.update(sql2);
|
||||
totalDeleted += deleted;
|
||||
log.info("[batch_step_execution] 삭제: {}건", deleted);
|
||||
|
||||
// 3. batch_job_execution_context
|
||||
String sql3 = String.format(
|
||||
"DELETE FROM %s.batch_job_execution_context WHERE job_execution_id IN (" +
|
||||
"SELECT job_execution_id FROM %s.batch_job_execution " +
|
||||
"WHERE create_time < NOW() - INTERVAL '%d days')",
|
||||
schema, schema, days);
|
||||
deleted = jdbcTemplate.update(sql3);
|
||||
totalDeleted += deleted;
|
||||
log.info("[batch_job_execution_context] 삭제: {}건", deleted);
|
||||
|
||||
// 4. batch_job_execution_params
|
||||
String sql4 = String.format(
|
||||
"DELETE FROM %s.batch_job_execution_params WHERE job_execution_id IN (" +
|
||||
"SELECT job_execution_id FROM %s.batch_job_execution " +
|
||||
"WHERE create_time < NOW() - INTERVAL '%d days')",
|
||||
schema, schema, days);
|
||||
deleted = jdbcTemplate.update(sql4);
|
||||
totalDeleted += deleted;
|
||||
log.info("[batch_job_execution_params] 삭제: {}건", deleted);
|
||||
|
||||
// 5. batch_job_execution
|
||||
String sql5 = String.format(
|
||||
"DELETE FROM %s.batch_job_execution WHERE create_time < NOW() - INTERVAL '%d days'",
|
||||
schema, days);
|
||||
deleted = jdbcTemplate.update(sql5);
|
||||
totalDeleted += deleted;
|
||||
log.info("[batch_job_execution] 삭제: {}건", deleted);
|
||||
|
||||
// 6. batch_job_instance (참조 없는 인스턴스만)
|
||||
String sql6 = String.format(
|
||||
"DELETE FROM %s.batch_job_instance WHERE job_instance_id NOT IN (" +
|
||||
"SELECT DISTINCT job_instance_id FROM %s.batch_job_execution)",
|
||||
schema, schema);
|
||||
deleted = jdbcTemplate.update(sql6);
|
||||
totalDeleted += deleted;
|
||||
log.info("[batch_job_instance] orphan 삭제: {}건", deleted);
|
||||
|
||||
log.info("[Spring Batch 메타] 보존기간: {}일, 총 삭제: {}건", days, totalDeleted);
|
||||
return totalDeleted;
|
||||
}
|
||||
|
||||
private int cleanupFailedRecord() {
|
||||
int days = config.getFailedRecordRetentionDays();
|
||||
String sql = String.format(
|
||||
"DELETE FROM %s.batch_failed_record WHERE status = 'RESOLVED' AND resolved_at < NOW() - INTERVAL '%d days'",
|
||||
schema, days);
|
||||
int deleted = jdbcTemplate.update(sql);
|
||||
log.info("[batch_failed_record] 보존기간: {}일 (RESOLVED만), 삭제: {}건", days, deleted);
|
||||
return deleted;
|
||||
}
|
||||
|
||||
private int cleanupRecollectionHistory() {
|
||||
int days = config.getRecollectionHistoryRetentionDays();
|
||||
String sql = String.format(
|
||||
"DELETE FROM %s.batch_recollection_history WHERE created_at < NOW() - INTERVAL '%d days'",
|
||||
schema, days);
|
||||
int deleted = jdbcTemplate.update(sql);
|
||||
log.info("[batch_recollection_history] 보존기간: {}일, 삭제: {}건", days, deleted);
|
||||
return deleted;
|
||||
}
|
||||
}
|
||||
@ -223,6 +223,13 @@ app:
|
||||
imo-column: imo_no # IMO/LRNO 컬럼명 (PK, NOT NULL)
|
||||
mmsi-column: mmsi_no # MMSI 컬럼명 (NULLABLE)
|
||||
|
||||
# 배치 로그 정리 설정
|
||||
log-cleanup:
|
||||
api-log-retention-days: 30 # batch_api_log 보존 기간
|
||||
batch-meta-retention-days: 90 # Spring Batch 메타 테이블 보존 기간
|
||||
failed-record-retention-days: 90 # batch_failed_record (RESOLVED) 보존 기간
|
||||
recollection-history-retention-days: 90 # batch_recollection_history 보존 기간
|
||||
|
||||
# 파티션 관리 설정
|
||||
partition:
|
||||
# 일별 파티션 테이블 목록 (네이밍: {table}_YYMMDD)
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user