EXPIRE_SESSIONS_JOB - zero1ne-26/doc GitHub Wiki
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 ๋ธ๋์น ํธ์๋ง๋ค ์๋์ผ๋ก:
Dockerfile.expire-sessions๋ก ์ด๋ฏธ์ง ๋น๋ghcr.io/<repository_owner>/orchestration-server-expire-sessions:latest๋ก ํ๊น- 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:[email protected]: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:[email protected]: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