DB 설정을 재기동 없이 자동으로 반영하는 방법
개요
요약
운영자가 설정값을 DB에서 바꾸면 각 에이전트 서버는 재기동 없이도 다음 요청을 처리할 때 그 변경을 스스로 감지해 반영한다. 이 자동 반영이 정확히 언제 어떤 기준으로 동작하는지 정리한다. 요청이 한 서버나 여러 서버에 동시에 몰릴 때는 어떻게 처리되는지도 함께 다룬다.
목차
- 전체 흐름
- 10초의 정확한 의미
- 설정 변경 시간은 어떻게 비교하나
- 서버를 처음 켤 때
- 사용자 요청이 들어올 때
- 상태별 동작
- 다중 요청이 들어올 때
- 요청 기반으로 만든 이유
- DB 변경은 어떻게 확인하나
- 변경을 발견하면 무엇이 바뀌나
- YAML 기본 설정
- 실패하거나 재기동이 필요한 경우
- 한 줄 답변
운영자가 ag_sys_config를 수정하면 각 에이전트 서버는 사용자 요청을 받을 때 변경 여부를 확인하고 설정을 다시 읽는다.
- 서버를 재기동하지 않아도 일반 설정이 반영된다.
- 별도 배치나 인스턴스 목록이 필요 없다.
- 서버가 여러 대여도 각자 스스로 최신 설정에 맞춰진다.
- DB 변경 여부를 확인하는 최소 간격은 10초다.
전체 흐름
서버 기동
→ YAML·환경변수로 최초 DB 접속 정보 확인
→ ag_sys_config 조회
→ get_settings()에 최종 설정 저장
→ 설정을 기준으로 그래프와 서비스 생성
사용자 요청 도착
→ 마지막 DB 확인 후 10초가 지났는지 메모리에서 확인
→ 10초 미만: DB 조회 없이 기존 설정으로 처리
→ 10초 이상: ag_sys_config의 최근 변경 시각과 행 수 조회
→ 변경 없음: 기존 설정으로 처리
→ 변경 있음: 설정과 관련 캐시를 비우고 다시 생성
→ 최신 설정으로 사용자 요청 처리그중에서도 10초라는 숫자가 정확히 무슨 뜻인지부터 짚고 넘어간다.
10초의 정확한 의미
요청이 들어온 뒤 10초를 기다리는 게 아니다. 사용자 요청이 들어올 때마다 지금이 DB를 다시 확인할 시점인지를 메모리에서 바로 판단한다.
사용자 요청 도착
→ 마지막 DB 확인 후 10초가 지났나?
→ 아니오: DB를 조회하지 않고 기존 설정으로 바로 처리
→ 예: 지금 바로 DB 조회그래서 요청마다 간단한 시간 비교는 하지만, 요청마다 DB를 조회하지는 않는다. 10초가 지난 뒤 들어오는 첫 요청만 DB를 조회한다.
ttl-seconds: 10이라는 이름을 쓰지만 실제 의미는 설정값의 만료 시간이 아니라 DB 변경 여부를 확인하는 최소 간격이다.
이 판단의 기준이 되는 두 시각을 비교하는 방법부터 살펴본다.
설정 변경 시간은 어떻게 비교하나
서버는 DB를 확인할 때 ag_sys_config의 가장 최근 updated_at을 기억해 둔다. 운영자가 설정을 수정하면 해당 행의 updated_at이 현재 시각으로 바뀐다.
서버가 이전에 기억한 max(updated_at)
→ 2026-08-20 10:00:00
운영자가 설정 수정
→ 현재 max(updated_at): 2026-08-29 15:30:00
다음 DB 확인
→ 이전 시간과 현재 시간이 다름
→ 설정 변경으로 판단
→ ag_sys_config 전체 다시 읽기
→ get_settings()와 관련 캐시 갱신여기에는 서로 다른 두 시간이 쓰인다.
- 마지막 DB 확인 시각: DB를 다시 조회할 수 있는 10초가 지났는지 판단하는 데 쓴다.
max(updated_at): 실제 설정값이 이전 확인 이후 바뀌었는지 판단하는 데 쓴다.
예를 들어 서버가 DB를 3초 전에 확인한 뒤 운영자가 설정을 수정했다면 바로 다음 요청은 기존 설정을 그대로 쓴다. 마지막 확인 후 10초가 지난 다음 들어온 첫 요청에서야 DB를 조회하고 변경을 반영한다.
이 판단 로직은 서버가 켜질 때부터 준비된다.
서버를 처음 켤 때
DB에 접속하려면 먼저 DB 주소를 알아야 하므로, 최초 접속 정보는 YAML과 환경변수에서 가져온다. 이 접속 정보만큼은 ag_sys_config에서 읽을 수 없다.
최초 get_settings()는 다음 정보를 합쳐 최종 설정을 만든다.
- 기본
application.yaml - 선택된 프로파일의
application-{profile}.yaml ag_sys_config- 환경변수
기본 운영 설정에서는 db-over-yml: true이므로 환경변수가 가장 먼저, 그다음 DB 설정이 YAML보다 우선한다. 로컬 프로파일은 테스트 편의를 위해 YAML을 우선하도록 설정돼 있다.
get_settings()는 매번 DB를 읽지 않도록 최종 설정을 메모리에 한 번 저장한다. 이후 이 설정으로 그래프, 워커 목록, 실행 계획, 프롬프트 설정 등 필요한 객체를 만든다.
서버 기동이 끝나면 그 시점의 ag_sys_config 상태도 비교 기준값으로 함께 저장한다.
이렇게 준비를 마친 서버에 실제로 요청이 들어오면 그때부터 확인이 시작된다.
사용자 요청이 들어올 때
설정 변경 확인은 백그라운드 타이머가 도는 방식이 아니라, 실제 사용자 요청이 들어와야 시작된다.
확인 대상 요청은 다음과 같다.
/agent/execute/agent/stream/agent/replay/agent/replay/stream/agent/hil/respond/agent/hil/stream-respond
요청마다 DB를 조회하지는 않는다. 마지막 DB 확인 후 10초가 지났을 때만 다시 확인하고 그사이 여러 요청이 동시에 들어와도 그중 하나만 확인을 수행한다.
요청이 없는 서버는 DB를 계속 조회하지 않는다. 나중에 첫 요청이 들어오면 그때 최신 설정을 확인한다.
요청이 어떤 상태에 있느냐에 따라 세부 동작은 조금씩 다르다.
상태별 동작
사용자 요청이 들어온 상태
사용자 요청 도착
→ 마지막 DB 확인 후 10초가 지났는지 확인
→ 지나지 않음: 기존 설정으로 바로 처리
→ 지남: DB 변경 여부 확인
→ 변경 없음: 기존 설정으로 처리
→ 변경 있음: 캐시 갱신을 최대 3초 기다린 뒤 처리설정 확인은 그래프를 실행하기 전에 이뤄진다. /agent/execute, /agent/stream, replay, HIL 응답 요청 모두 같은 방식이 적용된다.
HIL 응답을 기다리는 상태
그래프가 사용자 승인·추가 입력을 기다림
→ 별도 설정 확인 없음
→ HIL 응답 요청 도착
→ 10초 확인 간격이 지났으면 DB 변경 여부 확인
→ 변경이 있으면 캐시 갱신을 기다린 뒤 그래프 재개HIL(사용자 승인 대기) 상태 자체는 DB를 주기적으로 확인하지 않는다. 사용자가 승인·거절·추가 입력을 보내는 요청이 다음 확인의 방아쇠가 된다. 설정 캐시를 갱신해도 대기 중인 LangGraph MemorySaver 상태는 그대로 유지한다.
설정 반영이 3초를 넘기면 해당 요청은 기존 설정으로 진행하고 다음 요청에서 다시 확인한다.
요청이 없는 유휴 상태
사용자 요청 없음
→ 설정 확인 쿼리 없음
→ DB 설정이 변경돼도 즉시 동작하지 않음
→ 다음 사용자 요청 도착
→ 10초 확인 간격이 지났으면 DB를 확인하고 최신 설정으로 수렴유휴 상태에서는 별도의 폴링이나 배치가 돌지 않는다. 그만큼 불필요한 DB 조회가 없고 각 인스턴스는 자신에게 다음 요청이 들어오는 시점에 맞춰 최신 설정으로 수렴한다.
지금까지는 요청 하나를 기준으로 봤다. 요청이 한 번에 몰리거나 서버가 여러 대라면 처리 방식이 달라진다.
다중 요청이 들어올 때
마지막 DB 확인 시각과 확인용 락은 각 worker 프로세스의 메모리에서 관리한다. 그래서 동시 요청 처리는 같은 프로세스인지 다른 프로세스인지에 따라 달라진다.
같은 worker 프로세스에 요청이 몰리는 경우
요청 A·B·C가 동시에 도착
→ A·B·C 중 한 요청이 메모리 락을 먼저 획득
→ 해당 요청이 마지막 DB 확인 시각 갱신
→ 해당 요청만 ag_sys_config 변경 여부 조회
→ 나머지 요청은 중복 조회 생략동시에 도착해도 같은 프로세스 안에서는 한 요청만 DB를 확인한다. 먼저 도착한 요청이 아니라 운영체제와 스레드 실행 순서상 락을 먼저 획득한 요청이 확인을 담당한다.
- 변경이 없으면 모든 요청이 기존 설정으로 정상 처리된다.
- 변경이 있으면 확인을 담당한 요청이 설정 갱신을 시작하고 최대 3초까지 기다린다.
- 설정 갱신은 한 worker 프로세스에서 한 번만 실행된다.
- 나머지 요청은 10초 확인 간격 안의 요청이므로 확인을 건너뛰고 기존 설정으로 진행할 수 있다.
- 확인 간격을
0으로 설정하면 모든 요청이 변경 여부를 조회하지만 설정 갱신 작업은 하나로 합쳐서 처리한다.
이 방식은 DB 중복 조회와 요청 전체 대기를 줄이기 위한 것이다. 대신 설정이 바뀌는 순간에는 같은 프로세스 안에서도 확인을 담당한 요청은 새 설정을, 나머지 요청은 이전 설정을 쓰는 짧은 구간이 생길 수 있다.
보안 정책이나 라우팅처럼 모든 요청이 반드시 동시에 새 설정을 써야 한다면 갱신이 진행 중인 요청은 기존 _refresh_task를 함께 기다리도록 보완해야 한다.
worker 프로세스가 여러 개인 경우
같은 서버나 컨테이너 안에서도 worker 프로세스가 여러 개면 각 프로세스가 별도의 메모리 락과 마지막 DB 확인 시각을 가진다.
서버 1
├─ Worker Process 1 → 자체 락·확인 시각 → DB 확인 가능
├─ Worker Process 2 → 자체 락·확인 시각 → DB 확인 가능
└─ Worker Process 3 → 자체 락·확인 시각 → DB 확인 가능그래서 설정 확인 중복 방지 범위는 서버 전체가 아니라 worker 프로세스 하나다. 같은 시각에 모든 worker로 요청이 분산되면 worker마다 한 번씩 DB 확인 쿼리를 실행할 수 있다.
여러 인스턴스에 요청이 몰리는 경우
인스턴스 1에 요청 A·B 도착
→ A만 DB 확인
인스턴스 2에 요청 C·D 도착
→ C만 DB 확인
각 인스턴스
→ 변경 감지
→ 자기 캐시를 각각 갱신- 마지막 DB 확인 시각, 메모리 락, 설정 캐시는 인스턴스와 worker 프로세스끼리 공유하지 않는다.
- 같은 시점에 요청이 들어오면 활성 worker 프로세스마다 변경 확인 쿼리가 실행될 수 있다.
- 같은 worker 프로세스 안에서는 한 요청만 확인하므로 요청 수만큼 쿼리가 늘어나지는 않는다.
- 각 인스턴스는 다른 인스턴스에 갱신 요청을 보내지 않고 스스로 설정을 다시 읽는다.
- 요청이 없는 인스턴스는 그대로 있다가 다음 요청이 들어올 때 최신 설정으로 맞춰진다.
예를 들어 인스턴스가 3대이고 각 서버에 요청이 100개씩 동시에 들어와도 DB 확인 시점이라면, 각 인스턴스가 worker 1개일 때 변경 확인 쿼리는 요청 300건이 아니라 인스턴스별 1건씩 약 3건이 실행된다. 인스턴스마다 worker가 여러 개라면 확인 쿼리 수는 활성 worker 수만큼 늘어날 수 있다.
DB 변경 직후 요청이 들어오는 경우
- 해당 인스턴스의 마지막 DB 확인 후 10초가 지났으면 첫 요청이 변경을 바로 감지한다.
- 10초가 지나지 않았으면 그 요청은 기존 설정을 쓴다.
- 10초가 지난 뒤 들어오는 첫 요청이 변경을 감지하고 설정을 갱신한다.
- 그래서 반영 시점은
DB 변경 후 정확히 10초가 아니라확인 간격이 지난 뒤 들어온 첫 요청이다.
설정 갱신 중 DB 값이 다시 바뀌는 경우
- 갱신을 시작하기 전에 확인한 변경값을 기준으로 설정을 다시 읽는다.
- 그사이 DB가 한 번 더 바뀌면 다음 DB 확인에서 그 차이를 다시 발견한다.
- 변경을 놓치지 않고 한 번 더 갱신하는 방향으로 동작한다.
DB 확인이나 설정 갱신이 실패하는 경우
- 변경 확인 실패는 사용자 요청으로 전파하지 않고 기존 설정으로 처리한다.
- 실패한 인스턴스만 다음 확인 시점에 다시 확인한다.
- 다른 인스턴스는 각자 정상적으로 확인하고 갱신할 수 있다.
- 설정 갱신이 3초를 넘으면 기다리던 요청도 기존 설정으로 진행한다.
이렇게 설계한 데는 몇 가지 근거가 있다.
요청 기반으로 만든 이유
- 유휴 인스턴스가 10초마다 불필요하게 DB를 조회하지 않는다.
- 인스턴스 주소 목록이나 중앙 전파 서버가 필요 없다.
- 인스턴스가 늘거나 줄어도 별도 등록 없이 각자 최신 설정으로 맞춰진다.
- 변경을 발견한 요청은 실제 그래프 실행 전에 새 설정 적용을 기다릴 수 있다.
- DB 장애가 설정 확인을 넘어 사용자 요청 전체 장애로 번지지 않는다.
다만 모든 인스턴스가 요청 유무와 상관없이 10초 안에 반드시 같은 설정이 돼야 한다면 요청 기반보다 백그라운드 폴링이나 별도 변경 알림 방식이 더 적합하다.
실제 변경 여부는 집계 쿼리 하나로 확인한다.
DB 변경은 어떻게 확인하나
ag_sys_config를 수정하면 해당 행의 updated_at이 갱신된다. 서버는 다음 집계 쿼리 한 번으로 변경 여부를 확인한다.
select max(updated_at), count(*)
from ag_sys_config
where config_value is not nullmax(updated_at): 가장 최근에 수정된 시간count(*): 값이 있는 설정의 전체 개수
행 수를 함께 보는 이유는 설정 삭제 때문이다. 행이 삭제되면 updated_at은 남지 않지만 전체 행 수는 바뀌므로, 삭제도 감지할 수 있다.
전체 설정값을 매번 읽지 않고 변경 여부만 한 줄로 먼저 확인한 뒤, 실제 변경이 있을 때만 전체 설정을 다시 읽는다.
변경을 발견하면 무엇이 바뀌나
변경이 확인되면 먼저 새 설정을 정상적으로 읽을 수 있는지 검사한다. 성공했을 때만 기존 캐시를 비우고 새 설정을 적용한다.
다음과 같이 미리 저장해 둔 캐시들이 함께 갱신된다.
get_settings()설정 정보- 기본 그래프와 HIL 재개용 그래프
- 실행 오케스트레이션 서비스
- 워커와 에이전트 모듈 목록
- 실행 계획과 보고서 컬럼 규칙
- JWT, 임베딩 검색, 출력 가드레일 관련 설정
그래프 캐시는 새로 만들되, 실행 중 상태를 담고 있는 LangGraph MemorySaver는 그대로 유지한다. 설정이 바뀌었다는 이유로 승인 대기 중인 HIL 상태까지 사라지면 안 되기 때문이다.
변경을 감지한 요청은 기본 3초까지 새 설정 적용을 기다린다. 3초 안에 끝나면 최신 설정으로 요청을 처리하고 시간을 넘기면 기존 설정으로 처리한 뒤 다음 확인 때 다시 시도한다.
YAML 기본 설정
agent:
config:
db-over-yml: true
auto-refresh:
enabled: true
ttl-seconds: 10
apply-timeout-seconds: 3enabled: 자동 반영 사용 여부ttl-seconds: DB 변경 여부를 확인하는 최소 간격. 이름은 TTL이지만 실제로는 확인 쿨다운에 가깝고0이면 요청마다 확인한다.apply-timeout-seconds: 변경 감지 후 반영 완료를 기다리는 최대 시간.0이면 기다리지 않는다.
실패하거나 재기동이 필요한 경우
- 변경 여부 조회에 실패하면 사용자 요청은 기존 설정으로 정상 처리한다.
- 새 설정을 읽는 데 실패하면 기존 설정을 유지하고 다음 확인 시점에 다시 시도한다.
- DB가 잠시 불안정해도 사용자 요청 전체가 설정 확인 때문에 실패하지는 않는다.
- DB 주소, 포트, 커넥션 풀, 체크포인트 저장 방식처럼 기동 시점에 결정되는 값은 변경 자체는 감지되지만, 실제로 적용하려면 재기동이 필요하다.
한 줄 답변
서버는 최초 접속 정보로
ag_sys_config를 읽어 설정과 그래프를 만든다. 이후 사용자 요청이 올 때마다 10초 간격으로max(updated_at)과 행 수를 확인해, 변경이 있으면get_settings()와 관련 캐시(lru_cache)를 비운 뒤 최신 설정으로 그래프와 서비스를 다시 만든다.