2 Commits

Author SHA1 Message Date
Rinjae 8a884e53e3 ci - readiness probe port 39120 으로 정정
eapim-admin CI / build (push) Has been cancelled
- DEPLOY_HTTP_PORT 30120 → 39120 (실서버 tomcat 포트)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-16 16:30:13 +09:00
Rinjae 7de00ecad2 ci - readiness probe 안정화
eapim-admin CI / build (push) Has been cancelled
- probe URL 변경: login.do(POST) → loginForm.do(GET)
- timeout 180s → 300s (200MB war 첫 explode 시간 확보)
- 실패 시 catalina 로그 300줄 + systemd status + 포트 출력

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-16 16:22:07 +09:00
12 changed files with 24 additions and 180 deletions
@@ -46,39 +46,8 @@
var icon = rowObject.hasAttachment ? '<img src="' + iconPath + '" alt="File Attached" style="vertical-align: middle; margin-left: 5px; width: 16px; height: 16px;">' : '';
return cellvalue + icon;
}
function deleteSelectedRows() {
var selectedIds = $("#grid").jqGrid('getGridParam', 'selarrrow');
if (selectedIds.length === 0) {
alert('항목을 선택하세요.');
return;
}
if (!confirm('선택된 ' + selectedIds.length + '개 항목을 삭제하시겠습니까?')) {
return;
}
$.ajax({
type: "POST",
url: url,
dataType: "json",
data: {
cmd: 'DELETE_BULK',
ids: selectedIds.join(',')
},
success: function(data) {
alert('삭제되었습니다.');
$("#grid").jqGrid('clearGridData', true);
$("#grid").trigger("reloadGrid");
},
error: function(e) {
alert('삭제 중 오류가 발생했습니다.');
}
});
}
function init(){
$.ajax({
type : "POST",
@@ -134,8 +103,6 @@
autowidth: true,
viewrecords: true,
rowList : eval('[${rmsDefaultRowList}]'),
multiselect: true,
multiboxonly: true,
ondblClickRow: function(rowId) {
var rowData = $(this).getRowData(rowId);
var id = rowData['id'];
@@ -190,10 +157,6 @@
goNav(url2);
});
$("#btn_delete_selected").click(function(){
deleteSelectedRows();
});
$("select[name=searchUseYn], input[name^=search]").keydown(function(key){
if (key.keyCode == 13){
$("#btn_search").click();
@@ -216,7 +179,6 @@
<div class="search_wrap">
<button type="button" class="cssbtn" id="btn_new" level="W"><i class="material-icons">add</i> <%= localeMessage.getString("button.new") %></button>
<button type="button" class="cssbtn" id="btn_search" level="R"><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
<button type="button" class="cssbtn" id="btn_delete_selected" level="W" style="background-color: #dc3545; border-color: #dc3545; color: white;"><i class="material-icons">delete_forever</i> 선택 삭제</button>
</div>
<div class="title">공지사항 목록<span class="tooltip">공지사항을 관리합니다.</span></div>
<form id="ajaxForm" onsubmit="return false;">
@@ -15,6 +15,4 @@ public interface EMSScheduler {
void deleteAndAddJob(Scheduler scheduler, String jobName) throws SchedulerException, ClassNotFoundException;
void reloadJob(String jobName) throws SchedulerException, ClassNotFoundException;
}
@@ -120,32 +120,6 @@ public class EMSSchedulerImpl implements EMSScheduler {
}
}
@Override
public void reloadJob(String jobName) throws SchedulerException, ClassNotFoundException {
JobInfo jobInfo = jobInfoService.getById(jobName);
if (CLUSTERED.equals(jobInfo.getInstanceName())) {
reloadClusteredJob(jobInfo);
} else {
deleteAndAddJob(scheduler, jobInfo);
deleteJob(clusteredScheduler, jobName);
}
}
private void reloadClusteredJob(JobInfo jobInfo) throws SchedulerException, ClassNotFoundException {
TriggerKey triggerKey = new TriggerKey(getTriggerName(jobInfo.getId()), Scheduler.DEFAULT_GROUP);
Trigger existing = clusteredScheduler.getTrigger(triggerKey);
if (existing != null) {
CronTrigger newTrigger = newTrigger()
.withIdentity(triggerKey)
.withSchedule(cronSchedule(jobInfo.getCronExp()))
.build();
Date ft = clusteredScheduler.rescheduleJob(triggerKey, newTrigger);
log.info("{} rescheduled at: {} cron: {}", jobInfo.getId(), ft, jobInfo.getCronExp());
} else {
deleteAndAddJob(clusteredScheduler, jobInfo);
}
}
public void deleteJob(Scheduler inScheduler, String jobNm) throws SchedulerException {
JobKey key = new JobKey(jobNm, Scheduler.DEFAULT_GROUP);
JobDetail jobDetail = inScheduler.getJobDetail(key);
@@ -45,9 +45,6 @@ public class SchedulerManController extends BaseAnnotationController {
@Qualifier("monitoringSyncAgent")
private MonitoringSyncAgent monitoringSyncAgent;
@Autowired
private EMSScheduler emsScheduler;
@GetMapping(value = "/common/scheduler/schedulerMan.view")
public String viewList() {
return "/common/scheduler/schedulerMan";
@@ -99,11 +96,6 @@ public class SchedulerManController extends BaseAnnotationController {
@PostMapping(value = "/common/scheduler/schedulerMan.json", params = "cmd=UPDATE")
public ResponseEntity<Void> update(JobInfoUI jobInfoUI) {
service.update(jobInfoUI);
try {
emsScheduler.reloadJob(jobInfoUI.getId());
} catch (Exception e) {
logger.error("reloadJob error on current server", e);
}
syncReloadScheduler(jobInfoUI.getId());
return ResponseEntity.ok().build();
}
@@ -123,7 +115,7 @@ public class SchedulerManController extends BaseAnnotationController {
String url = "/monitoring/schedulerReload.do";
try {
ret = monitoringSyncAgent.targetSync(url, paramMap);
ret = monitoringSyncAgent.sync(url, paramMap);
} catch (Exception e) {
logger.error("syncReloadScheduler error", e);
} finally {
@@ -13,16 +13,10 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import java.util.List;
@Service
@Transactional(transactionManager = "transactionManagerForEMS")
public class PortalNoticeService extends AbstractEMSDataSerivce<PortalNotice, String, PortalNoticeRepository> {
public void deleteByIds(List<String> ids) {
repository.deleteAllById(ids);
}
public Page<PortalNotice> findAll(Pageable pageable, PortalNoticeUISearch portalNoticeUISearch) {
QPortalNotice qPortalNotice = QPortalNotice.portalNotice;
@@ -39,10 +39,11 @@ public interface ApiStatusRepository extends BaseRepository<ApiStatus, String> {
+ " FROM ("
+ " SELECT A.EAISVCNAME"
+ " , NVL(B.STATUS_CODE, 'N') AS STATUS_CODE"
+ " , NVL(( SELECT MAX('Y') FROM EMSAPP.DJB_APISTATUS_INCIDENT_API X"
+ " WHERE EXISTS (SELECT 1 FROM EMSAPP.DJB_APISTATUS_INCIDENT Y WHERE X.INCIDENT_ID = Y.INCIDENT_ID "
+ " AND SYSTIMESTAMP BETWEEN STARTED_AT AND END_AT) "
+ " AND A.EAISVCNAME = X.API_ID),'N') AS CTRL_YN "
//TODO: 게시판 임시로 생성하여 사용. 유차장이 완료하면 변경할것
+ " , NVL(( SELECT 'Y' FROM PTL_NOTICE_API X "
+ " WHERE EXISTS (SELECT 1 FROM EMSAPP.PTL_NOTICE Y WHERE X.NOTICE_ID = Y.ID)"
//+ " AND TO_CHAR(SYSDATE, 'YYYYMMDDHH24MI') BETWEEN START_TIME AND END_TIME) "
+ " AND A.EAISVCNAME = X.API_NAME),'N') AS CTRL_YN "
+ " , (SELECT CASE WHEN TOTAL = 0 THEN 'X'"
+ " WHEN (TOTAL - SUCCESS) * 100 / TOTAL > :errorRate THEN 'Y'"
+ " ELSE 'N' END"
@@ -1,9 +1,6 @@
package com.eactive.eai.rms.ext.djb.job;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.quartz.DisallowConcurrentExecution;
@@ -71,24 +68,10 @@ public class ApiStatusMonitorJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
// execute.instances 가 지정된 경우 해당 인스턴스에서만 실행
String allowedInstances = jobDataMap.getString("execute.instances");
if (StringUtils.isNotEmpty(allowedInstances)) {
Set<String> instanceSet = Arrays.stream(allowedInstances.split(","))
.map(s -> s.trim().toLowerCase())
.collect(Collectors.toSet());
String currentInstance = StringUtils.defaultString(System.getProperty("inst.Name")).trim().toLowerCase();
if (!instanceSet.contains(currentInstance)) {
log.debug("Job 실행 인스턴스 제한 - 현재: {}, 허용: {}", currentInstance, allowedInstances);
return;
}
}
log.info("*** START ApiStatusUpdateJob run({})", CommonUtil.getToday("yyyy-MM-dd HH:mm"));
// Job 파라미터 로깅
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
logJobParameters(jobDataMap);
HashMap<String, String> param = this.checkParameters(jobDataMap);
@@ -1,12 +1,8 @@
package com.eactive.eai.rms.ext.djb.job;
import java.util.Arrays;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobDataMap;
@@ -52,21 +48,6 @@ public class InflowTokenMonitorJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
// execute.instances 가 지정된 경우 해당 인스턴스에서만 실행
String allowedInstances = jobDataMap.getString("execute.instances");
if (StringUtils.isNotEmpty(allowedInstances)) {
Set<String> instanceSet = Arrays.stream(allowedInstances.split(","))
.map(s -> s.trim().toLowerCase())
.collect(Collectors.toSet());
String currentInstance = StringUtils.defaultString(System.getProperty("inst.Name")).trim().toLowerCase();
if (!instanceSet.contains(currentInstance)) {
log.debug("Job 실행 인스턴스 제한 - 현재: {}, 허용: {}", currentInstance, allowedInstances);
return;
}
}
log.info("*** START InflowTokenFailMonitorJob run({})", CommonUtil.getToday("yyyy-MM-dd HH:mm"));
long execMinute = 1; //default 배치 실행주기(분)
@@ -5,20 +5,14 @@ import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.common.util.CommonUtil;
import com.eactive.eai.rms.onl.apim.portalInquiry.PortalInquiryClosingService;
import com.eactive.eai.rms.onl.common.util.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 매일 00:05 실행 - RESPONDED 상태 문의글 자동 종료 배치
*
@@ -50,21 +44,6 @@ public class PortalInquiryClosingJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
// execute.instances 가 지정된 경우 해당 인스턴스에서만 실행
String allowedInstances = jobDataMap.getString("execute.instances");
if (StringUtils.isNotEmpty(allowedInstances)) {
Set<String> instanceSet = Arrays.stream(allowedInstances.split(","))
.map(s -> s.trim().toLowerCase())
.collect(Collectors.toSet());
String currentInstance = StringUtils.defaultString(System.getProperty("inst.Name")).trim().toLowerCase();
if (!instanceSet.contains(currentInstance)) {
log.debug("Job 실행 인스턴스 제한 - 현재: {}, 허용: {}", currentInstance, allowedInstances);
return;
}
}
log.info("*** START PortalInquiryCommentClosingService run({})", CommonUtil.getToday("yyyy-MM-dd HH:mm"));
int closingDays = DEFAULT_CLOSING_DAYS;
@@ -80,10 +80,4 @@ public class PortalNoticeManController extends BaseAnnotationController {
return ResponseEntity.ok().build();
}
@PostMapping(value = "/onl/apim/portalnotice/portalNoticeMan.json", params = "cmd=DELETE_BULK")
public ResponseEntity<String> deleteBulk(String ids) {
portalNoticeManService.deleteBulk(ids);
return ResponseEntity.ok().build();
}
}
@@ -33,7 +33,6 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@@ -283,20 +282,4 @@ public class PortalNoticeManService extends BaseService {
portalNoticeService.deleteById(id);
}
public void deleteBulk(String ids) {
if (StringUtils.isBlank(ids)) {
return;
}
List<String> idList = Arrays.asList(ids.split(","));
// 첨부파일 정리 (단건 삭제와 동일한 처리)
idList.forEach(id -> {
PortalNotice portalNotice = portalNoticeService.getById(id);
Optional.ofNullable(portalNotice.getFileId()).ifPresent(fileService::deleteFile);
});
portalNoticeService.deleteByIds(idList);
}
}
@@ -1,10 +1,10 @@
package com.eactive.eai.rms.onl.common.controller;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.eactive.eai.rms.common.interceptor.InterceptorSkipController;
import com.eactive.eai.rms.common.scheduler.EMSScheduler;
import com.eactive.eai.rms.onl.manage.adapter.spcftmadapter.AdapterJobInfo;
import com.eactive.eai.rms.onl.manage.adapter.spcftmadapter.AdapterSchedulerUtil;
import com.eactive.eai.rms.onl.manage.adapter.spcftmadapter.SpcfTmAdapterDao;
import org.quartz.Scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -15,11 +15,9 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.eactive.eai.rms.common.interceptor.InterceptorSkipController;
import com.eactive.eai.rms.common.scheduler.EMSScheduler;
import com.eactive.eai.rms.onl.manage.adapter.spcftmadapter.AdapterJobInfo;
import com.eactive.eai.rms.onl.manage.adapter.spcftmadapter.AdapterSchedulerUtil;
import com.eactive.eai.rms.onl.manage.adapter.spcftmadapter.SpcfTmAdapterDao;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@Controller
public class SchedulerReloadController implements InterceptorSkipController {
@@ -36,14 +34,19 @@ public class SchedulerReloadController implements InterceptorSkipController {
private EMSScheduler emsScheduler;
@Autowired
@Qualifier("scheduler")
@Qualifier("scheduler")
private Scheduler scheduler;
@Autowired
@Qualifier("clusteredScheduler")
private Scheduler clusteredScheduler;
@RequestMapping("/schedulerReload.do")
public ResponseEntity<Map<String, Object>> rmsSchedulerReload(String jobName) {
Map<String, Object> result = new HashMap<>();
try {
emsScheduler.reloadJob(jobName);
emsScheduler.deleteAndAddJob(scheduler, jobName);
emsScheduler.deleteAndAddJob(clusteredScheduler, jobName);
result.put("status", "success");
} catch (Exception e) {
logger.error("", e);