client_settings_json에서 데이터베이스 오류가 30분간 캐시됨 - 사이트 로드 실패

우선순위/심각도

드물지만 치명적인 문제입니다. 일시적인 데이터베이스 오류 발생 후 최대 30분 동안 사이트가 사용 불가능한 상태가 됩니다. 클라이언트 설정 누락으로 인한 JavaScript 오류로 인해 페이지가 제대로 로드되지 않습니다.

플랫폼

  • 영향 범위: 모든 Discourse 설치 환경
  • 확인된 환경: 일시적인 데이터베이스 연결 문제를 겪는 프로덕션 환경

설명

실제 결과
일시적인 데이터베이스 오류(연결 타임아웃, 풀 고갈, 네트워크 장애)가 발생하면 오류가 30분 동안 캐시됩니다. 이 기간 동안:

  • 사이트가 제대로 로드되지 않습니다 - 페이지가 깨지거나 작동하지 않는 상태로 표시됩니다.
  • 누락되거나 잘못된 설정으로 인해 클라이언트 측 JavaScript 오류가 발생합니다.
  • 모든 요청에서 “Nil client_settings_json from the cache for ‘client_settings_json_[git_version]’” 로그가 기록됩니다.
  • 브라우저에 빈 클라이언트 설정이 반환됩니다.
  • 데이터베이스가 완전히 복구된 후에도 이 상태가 지속됩니다.

기대되는 결과
일시적인 데이터베이스 오류가 발생하면 시스템은 오류를 캐시하지 않아야 합니다. 데이터베이스가 복구되면 다음 요청에서 클라이언트 설정을 성공적으로 가져와 캐시하고, 사이트가 즉시 정상적인 운영으로 복귀해야 합니다.

재현 단계

  1. 클라이언트 설정이 구성된 Discourse 인스턴스를 시작합니다.
  2. 데이터베이스 연결 문제를 시뮬레이션합니다(예: 연결 풀 고갈, 네트워크 지연 도입, 또는 포트 5432 일시적 차단).
  3. SiteSetting.client_settings_json을 트리거하는 요청을 수행합니다(어떤 페이지 로드든 이 동작을 수행합니다).
  4. 오류 관찰: “Error while generating client_settings_json_uncached: [database error]”
  5. 페이지가 올바르게 렌더링되지 않고, JavaScript 콘솔에 설정 누락과 관련된 오류가 표시됩니다.
  6. 데이터베이스 연결을 복구합니다.
  7. 다음 30분 동안 추가 요청을 수행합니다. 데이터베이스가 정상임에도 불구하고 “Nil client_settings_json from the cache” 오류가 계속 표시됩니다.
  8. 30분 후, 캐시가 만료되고 사이트가 마침내 복구됩니다.

사용자 영향

이 기간 동안 사이트는 사실상 다운된 상태입니다:

  • 페이지가 올바르게 렌더링되지 않습니다.
  • 설정 누락으로 인해 JavaScript 애플리케이션 초기화가 실패합니다.

이것은 1초간의 데이터베이스 일시 장애를 30분간의 중단으로 전환시킵니다.

근본 원인

lib/site_setting_extension.rb 파일에서 client_settings_json_uncached 메서드가 예외를 잡아 nil을 반환합니다. 이 nil 값이 30분 동안 캐시되어 사이트를 깨뜨립니다.

제안된 수정안

이 문제를 수정하기 위한 풀 리퀘스트가 제출되었습니다. 수정안은 nil을 반환하는 대신 예외를 다시 발생시키는(re-raise) 간단한 변경이 필요합니다.

이 방식이 작동하는 이유:

  1. 예외를 다시 발생시키면 Discourse.cache.fetch가 오류를 캐시하는 것을 방지합니다.
  2. 외부의 client_settings_json 메서드에는 캐시하지 않고 “”(빈 문자열)을 반환하는 적절한 예외 처리가 이미 존재합니다.
  3. 데이터베이스 문제 발생 중에도 사이트가 계속 기능할 수 있습니다(다만 성능이 저하될 수 있음).
  4. 데이터베이스가 정상 상태가 되면 다음 요청 시 사이트가 자동으로 복구됩니다.
  5. 이 수정안은 일시적인 데이터베이스 오류가 30분간의 중단을 유발하는 것을 방지합니다.

영향

이 버그는 일시적인 데이터베이스 문제를 겪는 모든 Discourse 설치 환경에 영향을 미칩니다:

  • 트래픽 급증 시 연결 풀 고갈
  • 애플리케이션과 데이터베이스 간의 네트워크 장애
  • 데이터베이스 페일오버 시나리오(예: 프라이머리/리플리카 전환)
  • site_settings 테이블의 잠금 경쟁(lock contention)
  • 느린 쿼리로 인한 쿼리 타임아웃

심각도: 이러한 일반적인 일시적 문제 중 어느 것이라도 근본적인 문제가 몇 초 만에 해결되더라도 전체 사이트가 30분 동안 사용 불가능하게 만듭니다.

우회 방법

지금 이 문제를 겪고 있다면, 수동으로 캐시를 지워 서비스를 복구할 수 있습니다:

Rails 콘솔에서

Discourse.cache.delete(SiteSettingExtension.client_settings_cache_key)
2개의 좋아요

잘 짚어주셨네요. PR을 확인해 보겠습니다.

5개의 좋아요

머지된 것 같은데, 정말 감사합니다.

2개의 좋아요