diff --git a/common_util/common_util_auth.py b/common_util/common_util_auth.py index e04d7d7c..0129110b 100644 --- a/common_util/common_util_auth.py +++ b/common_util/common_util_auth.py @@ -15,6 +15,7 @@ from config.config_system import ( DEVICE_TOKEN_COOKIE_NAME, EMAIL_REVERIFY_DAYS, PASSWORD_BCRYPT_ROUNDS, + SESSION_ACTIVITY_WRITE_INTERVAL_SECONDS, SESSION_COOKIE_NAME, SESSION_COOKIE_SECURE, SESSION_IDLE_TIMEOUT_SECONDS, @@ -127,11 +128,17 @@ async def verify_session(request: Request) -> dict[str, Any]: await connection.commit() raise HTTPException(status_code=401, detail="세션이 만료되었습니다.") - await cursor.execute( - "UPDATE sessions SET last_activity_at = CURRENT_TIMESTAMP WHERE id = %s", - (session_id,), - ) - await connection.commit() + # `last_activity_at` 은 유휴 판정(기본 4시간)에만 쓰는 값이라 초 단위로 정확할 이유가 + # 없다. 그런데 **요청마다** 쓰고 있어 원격 DB 왕복이 UPDATE + commit 으로 붙었다 + # (2026-09-06 실측: verify_session 34.4ms = SELECT 10.8 + UPDATE 10.4 + commit 9.5). + # 인증이 걸린 모든 요청이 지나는 자리라, 화면 한 번 여는 데 API 가 180번 나가면 + # 그만큼 곱해진다. 1분에 한 번만 쓴다 — 4시간 판정에는 영향이 없다. + if (now - row[4]).total_seconds() >= SESSION_ACTIVITY_WRITE_INTERVAL_SECONDS: + await cursor.execute( + "UPDATE sessions SET last_activity_at = CURRENT_TIMESTAMP WHERE id = %s", + (session_id,), + ) + await connection.commit() return { "session_id": row[0], "user_id": row[1], diff --git a/config/config_system.py b/config/config_system.py index be4eaef8..4a60494d 100644 --- a/config/config_system.py +++ b/config/config_system.py @@ -238,6 +238,12 @@ SESSION_COOKIE_NAME = os.getenv("SESSION_COOKIE_NAME", "session_id") DEVICE_TOKEN_COOKIE_NAME = os.getenv("DEVICE_TOKEN_COOKIE_NAME", "device_token") SESSION_MAX_AGE_SECONDS = int(os.getenv("SESSION_MAX_AGE_SECONDS", "43200")) SESSION_IDLE_TIMEOUT_SECONDS = int(os.getenv("SESSION_IDLE_TIMEOUT_SECONDS", "14400")) + +# `sessions.last_activity_at` 을 다시 쓰는 최소 간격(초). 유휴 판정이 4시간 단위라 초 단위로 +# 정확할 이유가 없고, 요청마다 쓰면 원격 DB 왕복이 약 20ms 씩 붙는다(2026-09-06 실측). +SESSION_ACTIVITY_WRITE_INTERVAL_SECONDS = int( + os.getenv("SESSION_ACTIVITY_WRITE_INTERVAL_SECONDS", "60") +) SESSION_COOKIE_SECURE = os.getenv("SESSION_COOKIE_SECURE", "True").lower() == "true" PASSWORD_BCRYPT_ROUNDS = int(os.getenv("PASSWORD_BCRYPT_ROUNDS", "12")) OTP_VALID_MINUTES = int(os.getenv("EMAIL_OTP_VALID_MINUTES", "5"))