[Open WebUI] 매 인증 요청마다 실행되는 last_active 업데이트를 단일 UPDATE 쿼리로 최적화
PR 링크: open-webui/open-webui#23215 상태: Merged | 변경: +3 / -8
들어가며
Open WebUI에서 update_last_active_by_id는 인증된 모든 요청에서 호출됩니다. 기존 구현은 사용자 행을 SELECT로 가져온 후, 필드를 수정하고, commit 후 refresh하여 전체 행을 다시 읽은 뒤 Pydantic 모델로 변환해 반환했습니다. 그런데 이 반환값을 사용하는 호출자가 없었습니다. 이 PR은 이를 단일 UPDATE 쿼리로 교체합니다.
핵심 코드 분석
Before: SELECT + commit + refresh + Pydantic 변환
def update_last_active_by_id(self, id: str, db=None) -> Optional[UserModel]:
try:
with get_db_context(db) as db:
user = db.query(User).filter_by(id=id).first() # SELECT
if not user:
return None
user.last_active_at = int(time.time())
db.commit()
db.refresh(user) # 전체 행 다시 SELECT
return UserModel.model_validate(user) # Pydantic 직렬화
except Exception:
return None
After: 단일 UPDATE 쿼리
def update_last_active_by_id(self, id: str, db=None) -> None:
try:
with get_db_context(db) as db:
db.query(User).filter_by(id=id).update(
{'last_active_at': int(time.time())}
)
db.commit()
except Exception:
pass
왜 이게 좋은가
- DB 라운드트립 감소: SELECT + UPDATE + SELECT(refresh) 3회에서 UPDATE 1회로 줄어든다. 매 인증 요청마다 실행되므로 효과가 누적된다.
- 불필요한 Pydantic 직렬화 제거: 반환값을 사용하는 호출자가 없으므로, UserModel 변환 비용을 완전히 제거했다.
- throttle 데코레이터와 결합: 이 메서드에는 이미 throttle 데코레이터가 적용되어 있어, 실행 빈도는 제한되지만 실행될 때의 비용을 최소화하는 것이 중요하다.
참고 자료
관련 포스트
PR Analysis 의 다른글
- 이전글 [sglang] Dumper 디버그 유틸리티 리팩토링: 설정 구조 개선과 Non-intrusive 모드 도입
- 현재글 : [Open WebUI] 매 인증 요청마다 실행되는 last_active 업데이트를 단일 UPDATE 쿼리로 최적화
- 다음글 [Open WebUI] 공유 채팅 삭제 시 전체 행 대신 ID만 조회하여 메모리 절약
댓글