ES /docs

[post_pointcloud_state_change_worker] Retrying 1 times, error: 504 Gateway Timeout

RCA: [post_pointcloud_state_change_worker] Retrying 1 times, error: 504 Gateway Timeout

Overview#

What Happened#

2026-04-30 16:34:19 UTC에 cupixvista-api-worker 서비스의 PostPointcloudStateChangeWorker가 Slack webhook (hooks.slack.com)에 pointcloud 상태 변경 알림을 전송하는 과정에서 504 Gateway Timeout을 수신했다. 단일 발생이며 Sidekiq retry를 통해 34초 후 자동 복구되었다.

Quick Facts#

Field Value
exception.class RestClient::GatewayTimeout
exception.message 504 Gateway Timeout
top_frame post_pointcloud_state_change_worker.rb:24
runtime Ruby (Rails / Sidekiq)
env production, us-west-2

Timeline#

  1. 2026-04-30T16:34:19ZPostPointcloudStateChangeWorker가 Slack webhook 호출 시 504 Gateway Timeout 수신, Sidekiq retry 시작
  2. 2026-04-30T16:34:53Z — Retry 성공, "Processing completed" 메시지 webhook 전송 완료 (hycrofteng-team3, capture 15915)
  3. 2026-05-01 — Error Sweeper가 클러스터 감지, RCA 수행

Error Log#

Datadog Logs

text
[post_pointcloud_state_change_worker] Retrying 1 times, error: 504 Gateway Timeout

Impact#

  • Service: cupixvista-api-worker
  • 발생 횟수: 1
  • 최초 발생: 2026-04-30T16:34:19.289Z
  • 최근 발생: 2026-04-30T16:34:19.289Z

실질적 영향 없음. Retry가 34초 후 성공하여 pointcloud 상태 알림은 정상 전달됨. 사용자 대면 기능에는 영향 없음 (Slack 내부 알림 채널만 관련).

Root Cause Summary#

Slack webhook 엔드포인트(hooks.slack.com)의 일시적 504 Gateway Timeout 응답이 원인이다. PostPointcloudStateChangeWorker(line 24)가 RestClient.post로 외부 Slack webhook을 호출하는데, Slack 인프라의 순간적 지연 또는 중간 프록시/CDN 타임아웃으로 504가 반환되었다. 이는 Cupix 내부 코드 결함이 아닌 외부 서비스의 일시적 장애(transient failure)이다.

Technical Analysis#

Code Path#

  • Entry point: app/models/concerns/notifiable/pointcloud.rb:48 — pointcloud 상태 변경 시 PostPointcloudStateChangeWorker.perform_async(message) 호출
  • Worker 실행: app/workers/post_pointcloud_state_change_worker.rb:13perform(message) 메서드 시작
  • HTTP 호출: app/workers/post_pointcloud_state_change_worker.rb:24RestClient.post SLACK_SERVICE_WEBHOOK_URL, data.to_json
  • Failure point: line 24에서 Slack이 504 응답 반환
  • Retry 로깅: app/workers/post_pointcloud_state_change_worker.rb:5-7sidekiq_retry_in 콜백에서 에러 로그 출력
app/workers/post_pointcloud_state_change_worker.rb:1-27ruby
class PostPointcloudStateChangeWorker
  include Sidekiq::Worker
  sidekiq_options queue: :default, retry: 2

  sidekiq_retry_in do |count, e|
    Cupix::Logger.error("[post_pointcloud_state_change_worker] Retrying #{count + 1} times, error: #{e.message}")
  end

  sidekiq_retries_exhausted do |job, e|
    Cupix.logger.error "[post_pointcloud_state_change_worker] Final retry attempt failed: #{job['args'].first}, error: #{e.message}"
  end

  def perform(message)
    channel = 'pointcloud-state'
    channel = "pointcloud-state-#{Rails.env}" unless Rails.env.production?

    data = {
      channel: channel,
      username: $SLACK_REGION_USER_NAME,
      icon_emoji: SLACK_REGION_ICON,
      text: message
    }

    RestClient.post SLACK_SERVICE_WEBHOOK_URL, data.to_json, content_type: :json
    Cupix::Logger.info("[post_pointcloud_state_change_worker] Successfully sent message to webhook: #{message}")
  end
end

기대 동작: RestClient.post가 Slack webhook에 JSON payload를 전송하고 200 OK를 수신한 후 성공 로그를 출력한다.

실제 동작: Slack이 504 Gateway Timeout을 반환하여 RestClient::GatewayTimeout 예외가 발생했고, Sidekiq의 sidekiq_retry_in 콜백이 에러 메시지를 로깅한 후 자동 retry를 수행했다.

주요 특징:

  • RestClient.post에 명시적 timeout 설정이 없어 기본값(open: 60s, read: 60s) 적용
  • retry: 2 설정으로 최대 2회 retry 가능 (총 3회 시도)
  • sidekiq_retry_in 콜백이 retry 횟수를 error 레벨로 로깅하여 error-sweeper에 감지됨

Log Evidence#

사용한 Datadog 쿼리:

text
service:cupixvista-api-worker status:error @environment:production "post_pointcloud_state_change_worker"

에러 발생 로그 (유일한 에러):

text
2026-04-30T16:34:19.289Z [error] [post_pointcloud_state_change_worker] Retrying 1 times, error: 504 Gateway Timeout

Retry 성공 로그 (34초 후):

text
2026-04-30T16:34:53.294Z [info] [post_pointcloud_state_change_worker] Successfully sent message to webhook - Processing completed (hycrofteng-team3, project axfvms, capture 15915)

동일 시간대 다른 성공 전송 로그:

text
2026-04-30T16:33:25.282Z [info] Successfully sent message to webhook - Processing completed (studiotecnicorodolfo, project ao4u1p, capture 15927)
2026-04-30T16:31:15.265Z [info] Successfully sent message to webhook - Waiting in queue (hycrofteng-team3, project axfvms, capture 15915)
  • 에러 전후 다른 webhook 전송은 모두 정상 — Slack의 일시적 장애임을 확인
  • cupixvista-api 서비스에는 동일 시간대 관련 에러 없음 — 하류 서비스 문제 아님

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 Slack webhook 인프라의 일시적 504 (transient failure) 단일 발생, 34초 후 retry 성공, 전후 동일 worker 성공 로그 존재, cupixvista-api에 관련 에러 없음 Confirmed
H2 내부 프록시/ALB 타임아웃 (outbound 요청 차단) 504는 일반적으로 프록시에서 발생 다른 webhook 전송은 동시간대 정상, 네트워크 전반 장애 징후 없음 Rejected
H3 RestClient 기본 timeout(60s) 초과로 인한 자체 타임아웃 timeout 미설정 에러 메시지가 "504 Gateway Timeout"(HTTP 응답)이며 "execution expired"(Ruby timeout)가 아님 Rejected

Fix Recommendation#

즉시 조치 (Critical)#

없음. 단일 발생이며 자동 복구됨. 코드 결함이 아닌 외부 서비스 일시적 장애.

단기 개선 (1주 이내)#

  • 로그 레벨 변경: sidekiq_retry_in 콜백(line 5-7)의 로그 레벨을 error에서 warn으로 변경. 외부 서비스 일시적 장애로 인한 retry는 정상 운영 시나리오이며, retry 실패 시(sidekiq_retries_exhausted)에만 error를 유지하는 것이 적절하다.
  • 명시적 timeout 설정: RestClient.posttimeout: 10, open_timeout: 5 옵션을 추가하여 불필요한 60초 대기를 방지.

장기 개선 (재발 방지)#

  • 외부 webhook 호출에 circuit breaker 패턴 적용 검토 (Slack 장애 시 불필요한 retry 및 queue 적체 방지)
  • Slack webhook 대신 Slack Web API (chat.postMessage)로 마이그레이션 시 더 세밀한 에러 핸들링 가능

Monitoring#

  • sidekiq_retry_in 로그를 warn으로 변경 후 별도 모니터 불필요
  • 반복 발생 시 아래 쿼리로 추적:
text
service:cupixvista-api-worker "post_pointcloud_state_change_worker" "504"

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: trivial