Skip to content

EXPIRE_SESSIONS_JOB

이준하 edited this page Aug 8, 2026 · 2 revisions

expire-sessions 배치 잡 — 빌드 & 배포 가이드

orchestration-server의 비활성 세션(24시간 이상 last_activity_at 갱신 없음)을 자동 종료(users.ended_at 세팅)하는 K8s CronJob.

소스: orchestration-server/cmd/expire-sessions, Dockerfile.expire-sessions 차트: devops/charts/job


1. 배경

orchestration-server는 세션(=사용자, users 테이블) 활성 상태를 두 가지 방식으로 관리한다.

방식 위치 주기 비고
인메모리 정리 루프 internal/mqttx/session_store.go SessionStore.StartCleanup 1분 서버 프로세스가 떠 있는 동안만 동작
K8s CronJob (이 문서) cmd/expire-sessions 스케줄 설정값 (기본 매시 13분) 서버 재시작 직후 공백 구간, 인메모리 상태 유실 등을 커버하는 이중 안전망

두 메커니즘 모두 같은 규칙을 쓴다: ended_at IS NULL AND last_activity_at < now - TTL 인 사용자를 ended_at = now로 종료 처리.

주의: ended_at을 세팅해도 MQTT 핸들러(task/start, task/complete, task/skip 등)는 현재 ended_at을 체크하지 않는다. 디바이스가 만료된 세션 ID로 계속 발행하면 서버는 여전히 처리한다 — 별도 이슈로 트래킹 중, 아직 미해결.


2. 빌드 (CI)

orchestration-server/.github/workflows/ci.yml의 expire-sessions-docker-build 잡이 main/master/develop 브랜치 푸시마다 자동으로:

  1. Dockerfile.expire-sessions로 이미지 빌드
  2. ghcr.io/<repository_owner>/orchestration-server-expire-sessions:latest로 태깅
  3. GHCR에 푸시 (버전 태그 없음, latest 단일 태그 — 용량 절약을 위해 backend/backoffice 이미지와 동일한 정책)

수동으로 로컬 빌드하려면:

cd orchestration-server
docker build -f Dockerfile.expire-sessions -t orchestration-server-expire-sessions:local .

3. 배포 (Helm)

차트: devops/charts/job — 상시 서비스(infra, backoffice)와 분리된 배치 전용 chart. 기본값은 expireSessions.enabled: false이므로 필요한 클러스터에서만 명시적으로 켠다.

3.1 DB 접속 정보

이 배치는 클러스터 내부 infra chart의 DB를 보지 않는다. 외부(운영) DB 주소를 직접 넘겨야 한다. 두 가지 방법:

A. 이미 존재하는 Secret 참조 (권장 — values에 평문 노출 없음)

kubectl create secret generic expire-sessions-db -n oc \
  --from-literal=database-url='postgres://user:pass@external-db.example.com:5432/orchestration?sslmode=require'

helm install job ./charts/job -n oc --create-namespace \
  --set expireSessions.enabled=true \
  --set database.existingSecret.name=expire-sessions-db \
  --set database.existingSecret.key=database-url

B. URL 값을 바로 넘겨서 chart가 Secret 생성

helm install job ./charts/job -n oc --create-namespace \
  --set expireSessions.enabled=true \
  --set database.url='postgres://user:pass@external-db.example.com:5432/orchestration?sslmode=require'

-n oc는 예시 namespace다. 어떤 namespace를 쓰든 Secret과 이 chart는 반드시 같은 namespace에 있어야 한다. namespace는 설치 후엔 못 옮기니(5.4 참고) 처음부터 정해서 시작하는 게 좋다.

3.2 설정값 (values.yaml 발췌)

키 기본값 설명
expireSessions.enabled false CronJob 생성 여부
expireSessions.image.repository ghcr.io/zero1ne-26/orchestration-server-expire-sessions 이미지
expireSessions.image.tag latest 태그
expireSessions.schedule "13 * * * *" 매시 13분 (정각 부하 회피)
expireSessions.sessionTtlHours 24 비활성 허용 시간
expireSessions.concurrencyPolicy Forbid 이전 실행이 안 끝났으면 새 실행 스킵
expireSessions.activeDeadlineSeconds 120 잡이 이 시간 넘게 돌면 강제 종료
expireSessions.backoffLimit 2 실패 시 재시도 횟수
database.url / database.existingSecret.* "" 위 3.1 참고

값을 바꾸고 싶으면 --set key=value를 추가하거나 -f my-values.yaml로 오버라이드한다.


4. 배포 후 확인

# CronJob 등록 확인
kubectl get cronjob -n oc

# 스케줄을 기다리지 않고 즉시 1회 실행해보기
kubectl create job --from=cronjob/job-expire-sessions manual-test-run -n oc

# 실행 로그 확인 (JSON 구조화 로그, expired 필드로 처리 건수 확인)
kubectl logs job/manual-test-run -n oc

# 과거 실행 이력 (successfulJobsHistoryLimit/failedJobsHistoryLimit 만큼 보관)
kubectl get jobs -n oc -l app.kubernetes.io/name=expire-sessions

정상 종료 시 로그 예:

{"level":"INFO","msg":"expire-sessions done","expired":3,"ttl_hours":24,"cutoff":"2026-08-07T13:13:00Z"}

5. 값 변경 & 운영 관리

5.1 값 하나만 빠르게 바꾸기

helm upgrade job ./charts/job -n oc --reuse-values \
  --set expireSessions.schedule="5 * * * *"
  • --reuse-values: 이번에 안 건드린 값(DB Secret 등)은 이전 설치 때 값 그대로 유지
  • -n oc: 설치할 때 쓴 namespace와 반드시 동일해야 함 (다르면 새 release로 취급되거나 리소스를 못 찾음)

5.2 값 파일로 관리하기 (권장)

--set을 계속 이어붙이는 대신, 바꿀 값을 파일 하나에 모아두고 그 파일로 upgrade하는 게 관리하기 쉽다:

# values-oc.yaml
expireSessions:
  enabled: true
  schedule: "5 * * * *"
database:
  existingSecret:
    name: expire-sessions-db
helm upgrade job ./charts/job -n oc -f values-oc.yaml

이 파일을 git에 커밋해두면 "지금 설정이 뭐였는지"를 파일 하나로 바로 확인할 수 있고, 다음에 값을 또 바꿀 때도 이 파일만 고쳐서 같은 명령을 반복하면 된다.

5.3 Headlamp에서 직접 고치면 안 되는 이유 (drift)

Headlamp(또는 kubectl edit)로 이미 떠 있는 CronJob 리소스의 spec.schedule을 직접 고치면 그 순간엔 적용된다. 하지만 Helm은 그 변경을 모른 채 "이 release의 값은 여전히 13분"이라고 기억하고 있어서, 나중에 (스케줄과 전혀 상관없는 값을 바꾸려는 것이었어도) helm upgrade를 한 번이라도 실행하면 Helm이 기억하는 값으로 조용히 되돌아간다.

  • 잠깐 테스트만 하고 버릴 거면 → Headlamp 직접 수정 OK
  • 계속 쓸 값이면 → 반드시 5.1/5.2처럼 Helm을 통해 바꿔서 Helm이 그 값을 "기억"하게 해야 함

5.4 네임스페이스는 나중에 못 바꾼다

Helm/K8s에는 이미 설치된 release의 namespace를 옮기는 기능이 없다. 잘못된 namespace에 설치했다면 지우고 다시 설치해야 한다:

# 1. 기존 namespace에서 제거
helm uninstall job -n default

# 2. DB Secret을 목표 namespace에 새로 생성 (Secret은 namespace 안에서만 보임)
kubectl create secret generic expire-sessions-db -n oc \
  --from-literal=database-url='postgres://...'

# 3. 목표 namespace에 재설치
helm install job ./charts/job -n oc --create-namespace \
  --set expireSessions.enabled=true \
  --set database.existingSecret.name=expire-sessions-db

5.5 제거

helm uninstall job -n oc

Clone this wiki locally