From db0461e416b26f1aad8046b9cf065608d43c889c Mon Sep 17 00:00:00 2001 From: HYOJIN Date: Mon, 16 Mar 2026 18:14:04 +0900 Subject: [PATCH 1/3] =?UTF-8?q?fix(=EC=8A=A4=EC=BC=80=EC=A4=84=EB=9F=AC):?= =?UTF-8?q?=20Quartz=20PostgreSQLDelegate=20=ED=95=84=ED=84=B0=EB=A7=81=20?= =?UTF-8?q?=EC=A0=9C=EC=99=B8=20=E2=80=94=20BYTEA=20=EC=BB=AC=EB=9F=BC=20?= =?UTF-8?q?=EC=9D=BD=EA=B8=B0=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?(#12)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - driverDelegateClass를 properties 필터에서 제외하여 PostgreSQLDelegate 유지 - StdJDBCDelegate가 PostgreSQL BYTEA 컬럼을 long으로 읽으려는 오류 해결 Co-Authored-By: Claude Opus 4.6 --- src/main/java/com/snp/batch/global/config/QuartzConfig.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/snp/batch/global/config/QuartzConfig.java b/src/main/java/com/snp/batch/global/config/QuartzConfig.java index ef35824..6d42e24 100644 --- a/src/main/java/com/snp/batch/global/config/QuartzConfig.java +++ b/src/main/java/com/snp/batch/global/config/QuartzConfig.java @@ -40,10 +40,11 @@ public class QuartzConfig { factory.setAutoStartup(false); // application.yml의 spring.quartz.properties 적용 - // jobStore.class와 driverDelegateClass는 setDataSource()가 내부적으로 설정하므로 제외 + // jobStore.class는 setDataSource()가 LocalDataSourceJobStore로 대체하므로 제외 + // driverDelegateClass는 PostgreSQLDelegate가 필요하므로 유지 Properties properties = new Properties(); quartzProperties.getProperties().forEach((key, value) -> { - if (!key.contains("jobStore.class") && !key.contains("driverDelegateClass")) { + if (!key.contains("jobStore.class")) { properties.put(key, value); } }); From d2c6c4114326ac87dbae680bd73dbda0760ef8d7 Mon Sep 17 00:00:00 2001 From: HYOJIN Date: Mon, 16 Mar 2026 18:19:22 +0900 Subject: [PATCH 2/3] =?UTF-8?q?chore:=20QA=20=ED=99=98=EA=B2=BD=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 --- src/main/resources/application-qa.yml | 167 ++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 src/main/resources/application-qa.yml diff --git a/src/main/resources/application-qa.yml b/src/main/resources/application-qa.yml new file mode 100644 index 0000000..571a8c0 --- /dev/null +++ b/src/main/resources/application-qa.yml @@ -0,0 +1,167 @@ +spring: + application: + name: snp-batch-validation + + # PostgreSQL Database Configuration + datasource: + url: jdbc:postgresql://10.26.252.39:5432/mdadb + username: mda + password: mda#8932 + driver-class-name: org.postgresql.Driver + hikari: + maximum-pool-size: 10 + minimum-idle: 5 + connection-timeout: 30000 + + # JPA Configuration + jpa: + hibernate: + ddl-auto: update + show-sql: false + properties: + hibernate: + dialect: org.hibernate.dialect.PostgreSQLDialect + format_sql: true + default_schema: std_snp_data + + # Batch Configuration + batch: + jdbc: + table-prefix: "std_snp_data.batch_" + initialize-schema: never # Changed to 'never' as tables already exist + job: + enabled: false # Prevent auto-run on startup + + # Thymeleaf Configuration + thymeleaf: + cache: false + prefix: classpath:/templates/ + suffix: .html + + # Quartz Scheduler Configuration - Using JDBC Store for persistence + quartz: + job-store-type: jdbc # JDBC store for schedule persistence + jdbc: + initialize-schema: never # Quartz tables manually created in std_snp_data schema + properties: + org.quartz.scheduler.instanceName: SNPBatchScheduler + org.quartz.scheduler.instanceId: AUTO + org.quartz.threadPool.threadCount: 10 + org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX + org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate + org.quartz.jobStore.tablePrefix: std_snp_data.QRTZ_ + org.quartz.jobStore.isClustered: false + org.quartz.jobStore.misfireThreshold: 60000 + + # Kafka Configuration (DEV) + kafka: + bootstrap-servers: localhost:9092 # TODO: DEV Kafka Broker IP/PORT 설정 + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.apache.kafka.common.serialization.StringSerializer + acks: all + retries: 3 + properties: + enable.idempotence: true + compression.type: snappy + linger.ms: 20 + batch.size: 65536 + max.block.ms: 3000 + request.timeout.ms: 5000 + delivery.timeout.ms: 10000 + +# Server Configuration +server: + port: 8041 +# port: 8041 + servlet: + context-path: /snp-api + +# Actuator Configuration +management: + endpoints: + web: + exposure: + include: health,info,metrics,prometheus,batch + endpoint: + health: + show-details: always + +# Logging Configuration (logback-spring.xml에서 상세 설정) +logging: + config: classpath:logback-spring.xml + +# Custom Application Properties +app: + batch: + chunk-size: 1000 + api: + url: https://api.example.com/data + timeout: 30000 + ship-api: + url: https://shipsapi.maritime.spglobal.com + username: 7cc0517d-5ed6-452e-a06f-5bbfd6ab6ade + password: 2LLzSJNqtxWVD8zC + ais-api: + url: https://aisapi.maritime.spglobal.com + webservice-api: + url: https://webservices.maritime.spglobal.com + schedule: + enabled: true + cron: "0 0 * * * ?" # Every hour + + # LAST_EXECUTION 버퍼 시간 (시간 단위) - 외부 DB 동기화 지연 대응 + last-execution-buffer-hours: 24 + + # ShipDetailUpdate 배치 설정 (dev - 기존과 동일하게 20건 유지) + ship-detail-update: + batch-size: 20 # dev에서는 문제 없으므로 기존 20건 유지 + delay-on-success-ms: 300 + delay-on-failure-ms: 2000 + max-retry-count: 3 + + # AIS Target 배치 설정 + ais-target: + since-seconds: 60 # API 조회 범위 (초) + chunk-size: 50000 # 배치 청크 크기 + schedule: + cron: "15 * * * * ?" # 매 분 15초 실행 + kafka: + enabled: false + topic: tp_Global_AIS_Signal + send-chunk-size: 5000 + fail-on-send-error: false + # AIS Target 캐시 설정 + ais-target-cache: + ttl-minutes: 120 # 캐시 TTL (분) - 2시간 + max-size: 300000 # 최대 캐시 크기 - 30만 건 + + # ClassType 분류 설정 + class-type: + refresh-hour: 4 # Core20 캐시 갱신 시간 (기본: 04시) + + # Core20 캐시 테이블 설정 (환경별로 테이블/컬럼명이 다를 수 있음) + core20: + schema: std_snp_svc # 스키마명 + table: tb_ship_main_info # 테이블명 + imo-column: imo_no # IMO/LRNO 컬럼명 (PK, NOT NULL) + mmsi-column: mmsi_no # MMSI 컬럼명 (NULLABLE) + + # 파티션 관리 설정 + partition: + # 일별 파티션 테이블 목록 (네이밍: {table}_YYMMDD) + daily-tables: + - schema: std_snp_data + table-name: ais_target + partition-column: message_timestamp + periods-ahead: 3 # 미리 생성할 일수 + # 월별 파티션 테이블 목록 (네이밍: {table}_YYYY_MM) + monthly-tables: [] # 현재 없음 + # 기본 보관기간 + retention: + daily-default-days: 14 # 일별 파티션 기본 보관기간 (14일) + monthly-default-months: 1 # 월별 파티션 기본 보관기간 (1개월) + # 개별 테이블 보관기간 설정 (옵션) + custom: + # - table-name: ais_target + # retention-days: 30 # ais_target만 30일 보관 From dc3de487c0d76faf585481cfd2ddac2112a93d73 Mon Sep 17 00:00:00 2001 From: HYOJIN Date: Mon, 16 Mar 2026 18:22:26 +0900 Subject: [PATCH 3/3] =?UTF-8?q?docs:=20=EB=A6=B4=EB=A6=AC=EC=A6=88=20?= =?UTF-8?q?=EB=85=B8=ED=8A=B8=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/RELEASE-NOTES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/RELEASE-NOTES.md b/docs/RELEASE-NOTES.md index 30a77fd..a4779d5 100644 --- a/docs/RELEASE-NOTES.md +++ b/docs/RELEASE-NOTES.md @@ -46,6 +46,7 @@ - 테스트용 IMO 목록 건수 제한 제거 (#32) - 타임라인 상세 화면 이동 오류 수정 및 실행 중 작업 상세 버튼 추가 (#34) - RECOLLECT 모드에서 Tasklet 자체 스킵으로 last_success_date 복원 로직 제거 (#50) +- Quartz PostgreSQLDelegate BYTEA 컬럼 읽기 오류 수정 (#12) ### 변경 - 실패 레코드 Upsert 패턴 적용 (동일 키 중복 방지) @@ -61,3 +62,4 @@ - 팀 글로벌 워크플로우 1.5.0 동기화 - 팀 워크플로우 v1.6.1 동기화 - 실행 확인 모달 시작/종료일시 항목 제거 +- QA 환경 설정 파일 추가