역할
SCW(Scheduler WAS)는 시간이 되면 알아서 도는 일을 맡는 서버임. 원래 APW에 있던 스케줄 기능을 2023-08-31에 떼어내 만듦. 전체 그림은 공개노트/개발/시스템 구성.
- 컨트롤러가 사실상 없음.
스케줄러 → 서비스 → DB구조임(예외: 스케줄러 제어 API 1개) - 아무도 SCW를 호출하지 않음. 자기 시계로 돎
- 부르는 쪽: 홈넷서버, 공공데이터포털, 이음(에너지플랫폼), LG ThinQ, APW
- SMS·푸시를 직접 보내지 않고 APW에 요청함. 공개노트/개발/모듈/APW 연계 서버
기술 스택
APW에서 떼어냈기 때문에 구성이 거의 같음.
| 항목 | 값 |
|---|---|
| 프레임워크 | Spring Boot 2.7.0, Java 8, Gradle, war 패키징(scw.war) |
| 영속성 | JPA + MyBatis 혼용 |
| DB | PostgreSQL smahdb |
| 포트 | 운영 WAS 8083 |
| 스케줄링 | ThreadPoolTaskScheduler + CronTrigger를 직접 제어함. @Scheduled를 쓰지 않음 |
| HTTP 클라이언트 | WebClient(홈넷용·LG용 유틸 분리). 외부 호출 타임아웃 20초 |
| 톰캣 | /usr/local/tomcat-scw/. 기동은 startup_proxy.sh(Squid 프록시 경유) |
| 로그 | /app/logs/was/tomcat-scw/scw.log, scw_error.log (일별 롤링, 30일 보관) |
| 로그 패턴 | [traceId=...] 포함. 스케줄 실행 단위로 traceId가 붙음 |
| Jenkins 잡 | (DEV/PROD)-lh-smah-server-scw |
설정 주소가 DB에 있음
smah.api.url, to.eepapi.api.url 같은 설정값은 주소가 아니라 cmn.tb_cstt_m의 상수 ID임. 런타임에 DB에서 실제 값을 꺼내 씀.
APW 주소나 에너지플랫폼 주소를 바꾸려면 설정 파일이 아니라 DB의
cmn.tb_cstt_m을 고쳐야 함. 재배포가 필요 없는 대신, 소스만 봐서는 실제 호출 대상을 알 수 없음.
스케줄러 공통 동작 (가장 중요)
기동 순서
- 서버가 뜨면 각 스케줄러가 기본 주기 1분으로 먼저 시작함
- 1분 뒤 첫 실행에서
cmn.tb_proc_m을 읽음(proc_nm= 스케줄러 이름,us_yn = 'Y') - Active WAS인지 판정함. 아니면 스스로 종료함
- 맞으면 DB의 cron 값으로 주기를 바꾸고 스케줄러를 재시작함
- 이후부터는 DB에 적힌 주기로 돎
cron 표현식은 소스에 없음. 전부
cmn.tb_proc_m.cron_xprssn_vl에 들어 있음. 현재 주기를 보려면cmn.tb_proc_m에서proc_nm이SCW_로 시작하는 행의cron_xprssn_vl,pod_cd,pod_hr,us_yn,actv_trg_svr_id,actv_trg_svr_ip,proc_desc를 조회할 것.
같은 테이블을 통계 배치도 씀. SCW는 cron_xprssn_vl이 있는 행, 배치는 cron_schdl_yn='N'인 행을 담당함. 공개노트/개발/모듈/통계 배치 서버
Active WAS 판정 (이중화)
tb_proc_m의 Active 서버 IP와 호스트명을 읽어 현재 서버와 비교함. 둘 다 맞아야 Active로 봄- Active가 아니면 스케줄러를 완전히 끄고
Active 대상 WAS 가 아닙니다...스케줄러 종료됨로그를 남김 - 한 번 꺼지면 WAS를 재시작할 때까지 다시 돌지 않음
확인 필요
WAS 2대에 SCW를 모두 띄우면 Active가 아닌 쪽은 기동 1분 뒤 스케줄러가 전부 꺼짐. 자동 failover가 없음. Active 서버를 교체하려면
tb_proc_m의 Active 서버 IP·호스트명을 바꾸고 새 Active WAS를 재시작해야 함. 이 절차가 운영 매뉴얼에 있는지 확인 필요. Active 호스트명은 서버가 스스로 읽는 호스트명과 정확히 같아야 하므로(DNS 설정에 따라 FQDN이 될 수 있음) 운영값 확인도 필요함.
실행 주기와 데이터 조회 범위 (pod_hr)
예약 기반 스케줄(이벤트 전달, IoT 예약 제어, AutoDR 제어)은 cron 주기와 별개로 얼마나 넓은 시간 범위의 데이터를 가져올지를 tb_proc_m.pod_hr(분)로 정함.
- 과거 조회형(이벤트 전달):
지금 - pod_hr분~지금에 생긴 데이터를 전달함 - 미래 예약형(IoT·AutoDR 제어):
지금~지금 + pod_hr분예약을 가져와 스케줄러 안에서 시간 맞춰 실행함
cron 주기와
pod_hr은 항상 같게 맞춰야 함.pod_hr이 작으면 그만큼 데이터가 누락되고, 크면 중복 발송됨.
실행 이력
실행할 때마다 cmn.tb_proc_run_h에 결과를 남김. 장애 진단은 여기부터 봄.
결과값이 통일되어 있지 않음 — COMPLETE, COMPLITE(오타), FAIL이 섞여 있고, DB 배치 쪽은 같은 테이블에 0(실행중)/1(성공)/2(오류) 체계로 씀. 모니터링 쿼리를 짤 때 주의할 것. 배치 쪽 체계는 공개노트/개발/모듈/통계 배치 서버.
스케줄러 제어 API
SCW에 있는 유일한 컨트롤러임. POST /api/smh/schedulerExecuteAction(헤더 ApiKey)으로 시스템관리자 화면(SMW)에서 시작·중지·주기 변경을 함. 스스로 꺼진 스케줄러를 다시 켜는 방법은 WAS 재기동 또는 이 API뿐임.
스케줄 목록
주기는 전부 DB에 있으므로 아래 “주기”는 소스 주석 기준 추정임.
동작 중 (15개)
| proc_nm | 하는 일 | 주기(추정) | 상세 |
|---|---|---|---|
SCW_SCHEDULER_GET_HOUSEHOLD_TERMINAL | 홈넷서버에서 단지별 세대단말기(월패드) 목록·상태 수집 | 매일 | 아래 |
SCW_SCHEDULER_CONTROL_AUTODR_DEVICE | AutoDR 발령에 따라 홈넷 기기 제어 | 분 단위 | 공개노트/기능/AutoDR |
SCW_SCHEDULER_CONTROL_USER_IOT_DEVICE | 입주민이 예약한 IoT 기기 제어 실행 | 분 단위 | 공개노트/기능/우리집제어 |
SCW_SCHEDULER_EVENT_SMARTHOME_NOTIFICATION_HOUSEHOLD | 세대별 이벤트를 홈넷서버로 전달 | 분 단위 | 공개노트/기능/홈넷 이벤트 알림 |
SCW_SCHEDULER_EVENT_SMARTHOME_NOTIFICATION_SUBDIVISION | 단지별 이벤트를 홈넷서버로 전달 | 분 단위 | 공개노트/기능/홈넷 이벤트 알림 |
SCW_SCHEDULER_CANCEL_SUBSCRIBE_DEVICE_EVENT | 리프레시 토큰이 만료된 사용자의 기기 이벤트 구독 해지 | 공개노트/기능/홈넷 이벤트 알림 | |
SCW_SCHEDULER_EVENT_VACANT_HOUSEHOLD_MOVE_OUT | 공가세대에 남은 입주확정 사용자를 전출 처리 | 아래 | |
SCW_SCHEDULER_GET_AIR_QUALITY | 공공데이터포털 대기질 조회 | 아래 | |
SCW_SCHEDULER_GET_SHORTERM_FORECAST | 공공데이터포털 단기예보 조회 | 아래 | |
SCW_SCHEDULER_GET_WEATHER_CONDITION | 공공데이터포털 기상개황 조회 | 아래 | |
SCW_SCHEDULER_GET_WEATHER_WARNING | 공공데이터포털 기상특보 조회 | 아래 | |
SCW_SCHEDULER_GET_AUTODR_EXA_DTLS | 에너지플랫폼에서 AutoDR 정산내역 조회·적재 | 매달 | 공개노트/기능/AutoDR |
SCW_SCHEDULER_GET_LHECR_NC | LH살피미 임계치 초과 확인 → SMS 발송 요청 | 1시간마다 | 아래 |
SCW_SCHEDULER_GET_TKMDCN_NC | 복약 대상자에게 복약 푸시 알림 | 아래 | |
SCW_SCHEDULER_REFRESH_LG_TOKEN | LG ThinQ API 토큰 갱신 | 공개노트/기능/우리집제어 |
비활성 (4개, 주석 처리됨)
홈넷서버 정보·상태 동기화, 주거약자(안전서비스) 세대 동기화, 구 버전 날씨 수집, 구 버전 복약 알림 클래스 4개가 주석 처리된 채 남아 있음. 이관하면서 옮기지 않은 기능이라 proc_nm도 아직 APW_SCHEDULER_*임.
홈넷서버 정보·상태 동기화와 주거약자 세대 동기화는 현재 아무도 자동으로 하지 않음. 세대단말기 스케줄러가 대신하거나 수동 처리하는 것으로 보임(추정).
기능 상세
세대단말기 정보 수집
각 단지 홈넷서버에 세대 월패드 목록을 물어 cmn.tb_hsh_ter_m을 통째로 현행화함. 관리자 화면의 단말기 조회가 이 데이터를 봄.
- 홈넷서버
GET /api/lh2hn/gateways를 페이징으로 반복 호출함 - 응답을 세션 기반 임시테이블에 넣고 중복 제거 → 동·호로 세대ID 매핑 → 이력 이관 후 갱신·삽입·삭제 처리함
- 임시테이블을 쓰는 이유는 PostgreSQL Vacuum 지연을 피하기 위함임. 세션 기반이라 외부에서 진행 상황을 볼 수 없음
운영 시 알아둘 점
- 한 단지가 실패하면 전체가 롤백됨(메서드 전체가 하나의 트랜잭션임). 인수인계 문서에도 개선 과제로 적혀 있음
- “단말기 목록이 어제 것이다” → 이 스케줄러가 어젯밤에 실패한 것임.
cmn.tb_proc_run_h에서 마지막 결과를 볼 것 - 동·호가 세대 테이블에 없는 단말기는
unknown으로 걸러짐. 신규 입주 단지에서 세대 등록이 안 된 경우 여기 걸림. 기본매뉴얼/관리사무소/새로 연동한 단지의 단말기 조회가 안 돼요
공가세대 전출 처리
세대가 공가인데 입주확정 사용자가 남아 있으면 APW POST /api/smh/cogo/move-out으로 전출 처리를 요청함. 데이터 정합성 보정용임.
이 처리가 돌면 파트너 가전 연동 해지·홈넷 전출 이벤트 전달까지 연쇄로 일어남. 대량 처리 시 부하에 주의. 전출 처리 내용은 공개노트/기능/로그인과 세대 승인.
날씨·대기질 수집 (공공데이터포털 4종)
| 대상 | 저장 테이블 |
|---|---|
| 대기질 | hc.tb_arqlt_l |
| 단기예보 | hc.tb_strm_frcst_l |
| 기상개황 | hc.tb_wthrcnd_frcst_l |
| 기상특보 | hc.tb_wthrwrn_l |
- 주소와 인증키는 전부
cmn.tb_cstt_m에 있고 인증키(SCW_DATA_API_KEY)는 4종 공통임 - 주소나 키가 비어 있으면 호출하지 않고 조용히 넘어감
- 조회 기준은 단지별 격자좌표(단기예보), 측정소 정보(대기질), 지점코드(기상개황), 전국 일괄(기상특보)임
운영 시 알아둘 점
- 공공데이터포털 인증키는 만료됨. 만료되면
cmn.tb_cstt_m의 키를 갱신해야 함 - 저장이 덮어쓰기 방식이라 수집이 멈춰도 데이터가 지워지지 않고 오래된 값으로 남음. 위 테이블의 최종 갱신 시각으로 진단할 것
- 앱·월패드가 보는 날씨는 이 테이블을 읽는 DB 함수(
sf_*_wthr_*_for_usr)가 만듦. 공개노트/개발/모듈/통계 집계 DB 함수, 공개노트/개발/모듈/MAW 앱 API 서버 - 수집이 밀리면 일 3시 프로시저
sp_ev_if_gdata가 수신율 50% 미만을 감지해SE004이벤트를 띄움. 공개노트/개발/모듈/통계 집계 DB 함수 - 구 버전 날씨 테이블(
cmn.tb_sbd_wthr_m,cmn.tb_sbd_arqlt_m)이 아직 남아 있어 두 세대의 날씨 테이블이 공존함
LH살피미 알림
LH살피미(독거 어르신 안전확인 센서)가 일정 시간 이상 반응이 없으면 보호자에게 SMS를 보냄. 발송은 APW POST /api/smh/sms에 요청함. 공개노트/개발/모듈/SMS 발송
- 임계치는 세대별 안전서비스 설정값(시간 단위)임
- 발송 후 이벤트 발생 내역을 갱신해 중복 발송을 막음
- 1시간 주기이므로 최대 1시간 늦게 감. “왜 늦게 왔냐”는 문의의 답임
- APW가 죽어 있으면 SMS가 나가지 않음
복약 알림
복약 시간이 된 대상자와 그 가족에게 푸시를 보냄. 발송은 APW POST /api/smh/push에 요청함. 공개노트/개발/push 알림
구 버전 클래스(비활성)와 현재 클래스가 같은 proc_nm을 씀. 둘 다 켜면 중복 발송됨. 클래스 이름도 Taking/Talking으로 혼동됨.
앱 서버(MAW)에는 스케줄러가 없음.
@Scheduled·@EnableScheduling·cron 표현식이 MAW 전 소스에 0건임(2026-09-18 확인). MAW는 약 등록·복약 기록·기기 예약을 저장만 하고, 시간이 되어 실행하는 일은 전부 SCW 몫임. 그래서 “복약 알림이 안 온다”, “예약이 실행되지 않는다”, “전출이 반영 안 된다”는 MAW 로그로 추적할 수 없고 여기 실행 이력을 봐야 함. 공개노트/기능/헬스케어
외부 연동
| 대상 | 인증 | 실패 시 |
|---|---|---|
| 홈넷서버 | Authorization: Bearer (토큰은 APW에서 받아옴) | 건별 로그 + tb_proc_run_h. 세대단말기 수집만 전체 롤백 |
| APW | ApiKey 헤더(cmn.tb_cstt_m) | APW가 멈추면 SMS·푸시·홈넷 제어가 전부 멈춤 |
| 에너지플랫폼(이음) | auth 헤더 + vendor-id | 정산 데이터 미적재 |
| 공공데이터포털 | serviceKey 파라미터 | 날씨가 오래된 값으로 고정됨 |
| LG ThinQ | 파트너 API 키·시크릿 | 단지별 건별 실패 허용 |
- 모든 외부 호출이 Squid 프록시를 탐. war로 구동하므로 프록시 설정은
catalina.sh에 있어야 하고, 그래서 기동 스크립트가startup_proxy.sh임 - 홈넷서버 SSL은 LH가 배포한 사설 인증서임. 공개노트/기능/홈넷 서버 연동
- API 송수신 이력은 APW와 같은
alog스키마 테이블에 남음
데이터
스케줄 제어
| 테이블 | 용도 |
|---|---|
cmn.tb_proc_m | 스케줄 설정. 아래 컬럼 표 참고 |
cmn.tb_proc_run_h | 스케줄 실행 이력. 장애 진단은 여기부터 |
cmn.tb_cstt_m | 상수(외부 주소, API 키) |
tb_proc_m 주요 컬럼
| 컬럼 | 의미 |
|---|---|
proc_nm | 스케줄러 식별자(SCW_SCHEDULER_*). 소스의 이름과 정확히 같아야 함 |
cron_xprssn_vl | cron 표현식(초 포함 6자리) |
us_yn | Y가 아니면 설정을 못 읽고 그냥 넘어감 |
actv_trg_svr_id / actv_trg_svr_ip | Active WAS 호스트명 / IP. 둘 다 현재 서버와 같아야 함 |
pod_cd / pod_hr | 주기 코드(m=분) / 데이터 조회 범위(분). cron 주기와 같게 맞출 것 |
proc_desc | 설명. 인수인계 문서가 “기능 목록은 이 컬럼을 보라”고 안내함 |
업무 테이블
- 홈넷·단지:
cmn.tb_smah_sbd_d,cmn.tb_hnsvr_m,cmn.tb_hnsvr_tkn_d,cmn.tb_hsh_m,cmn.tb_usr_m,cmn.tb_hsh_ter_m,smah.tb_hsh_ter_ss_l,cmn.tb_cogo_h,cmn.tb_oauth_m,cmn.tb_ptnr_m,cmn.tb_ptnr_sbd_d - 업무:
smah.tb_dr_goo_l(DR 발령),smah.tb_atdr_cont_l(AutoDR 제어 결과),smah.tb_dr_ctctr_m,smah.tb_dr_exa_l(정산),smah.tb_cont_schdl_m·_h·_fil_l(IoT 예약·이력·실패),smah.tb_hsh_mngexp_m,smah.tb_hsh_rfe_m,smah.tb_elc_vt_m,cmn.tb_rsd_annc_fcts_l,cmn.tb_evn_occ_l - 날씨·헬스케어(
hc): 위 날씨 4종,hc.tb_arqlt_msrsttn_m,hc.tb_lhecr_pod_brf_l(살피미 주기보고),hc.tb_tkmdcn_*(복약)
알려진 이슈
- 세대단말기 스케줄러가 전 단지를 하나의 트랜잭션으로 묶음. 한 단지 홈넷서버가 응답을 안 주면 그날 전 단지 갱신이 무효가 됨
- 관리비·임대료 푸시가 세대별 토픽 발송이라 느림. 단지별 1회 발송으로 바꾸면 개선됨(우선순위 낮음)
- Active WAS 자동 failover 없음.
tb_proc_m수정 + WAS 재시작이 수동으로 필요함 - 스케줄러가 스스로 꺼진 뒤 다시 켜지지 않음
- 비활성 스케줄러 4개가 남아 있음. 홈넷서버 상태·주거약자 세대 동기화가 현재 자동으로 돌지 않음
- 복약 알림 클래스 2개가 같은
proc_nm을 씀. 둘 다 켜면 중복 발송됨 - 홈넷 호출 포트 8094가 하드코딩됨. APW는 DB에 포트가 있으면 그걸 쓰는데 SCW는 무조건 8094를 붙임. 홈넷사가 다른 포트를 쓰면 SCW 쪽만 실패함
- 기기 이벤트 구독 해지가 JWT 검증 예외를 전부 “만료”로 간주함. 서명키를 바꾸면 전 사용자 구독이 해지될 수 있음
tb_proc_run_h결과 코드가 통일되지 않음(COMPLETE/COMPLITE/FAIL+ 배치의0/1/2)- 전입·전출 이벤트가 신·구 코드로 중복 발송됨(연동규격 V1.0 → V1.1 전환 중). 홈넷사가 둘 다 처리하면 이중 처리될 수 있음
- 로컬 SSL 검증 해제 코드가 여러 서비스에 복사되어 있음. 프로필이 잘못 들어가면 운영에서 인증서 검증이 꺼짐. 로그에
ssl secure 모드가 해제 되었으니 주의필요가 보이면 프로필 오류임 - jasypt·ARIA·JWT 키가 설정 파일에 평문임(APW와 같은 문제)
- 설정 주소가 DB에 있어 소스만으로는 실제 호출 대상을 알 수 없음
확인 필요
확인 필요
- 운영
cmn.tb_proc_m의 실제 등록 내역을 확인해야 함. 이 페이지의 주기는 전부 추정임- 각 스케줄러의 cron 주기와
pod_hr이 일치하는지. 불일치하면 이벤트 누락 또는 중복 발송이 생김- LG 토큰 갱신 주기가 LG 토큰 유효기간보다 짧은지. 길면 중간에 만료 구간이 생김
- 주거약자 세대 정보와 홈넷서버 상태를 현재 무엇이 갱신하는지. 스케줄러가 비활성인데 데이터는 최신인지
- 복약 알림 구 클래스를 지워도 되는지
- 배포 후 스케줄러가 정상 기동했는지 확인하는 절차가 있는지(기동 1분 뒤 로그의
스케줄러 시작함 : [cron]으로 확인 가능)- 공공데이터포털 인증키의 만료일과 갱신 담당자
관련
공개노트/개발/시스템 구성 공개노트/개발/모듈/APW 연계 서버 공개노트/개발/모듈/MAW 앱 API 서버 공개노트/개발/모듈/OAW 인증 서버 공개노트/개발/모듈/통계 배치 서버 공개노트/개발/모듈/통계 집계 DB 함수 공개노트/기능/AutoDR 공개노트/기능/홈넷 이벤트 알림 공개노트/기능/우리집제어 공개노트/개발/모듈/SMS 발송 공개노트/개발/push 알림 기본매뉴얼/운영/tomcat과 배치 기동 기본매뉴얼/운영/WAS 로그 확인