구독 관련 500 오류 문제

이것은 #contribute:bug로 보이지만, 무슨 일이 일어나고 있는지 알 수 없습니다.

사용자 중 일부가 /s/user/subscriptions/를 로드하려고 할 때 500 에러를 겪고 있습니다. (/my/billing/subscriptions를 방문할 때)

NoMethodError (undefined method `[]' for nil) app/controllers/application_controller.rb:427:in `block in with_resolved_locale' app/controllers/application_controller.rb:427:in `with_resolved_locale' l


NoMethodError (undefined method `[]' for nil)
app/controllers/application_controller.rb:427:in `block in with_resolved_locale'
app/controllers/application_controller.rb:427:in `with_resolved_locale'
lib/middleware/omniauth_bypass_middleware.rb:35:in `call'
lib/content_security_policy/middleware.rb:12:in `call'
lib/middleware/anonymous_cache.rb:410:in `call'
lib/middleware/csp_script_nonce_injector.rb:12:in `call'
config/initializers/008-rack-cors.rb:14:in `call'
lib/middleware/default_headers.rb:13:in `call'
config/initializers/100-quiet_logger.rb:20:in `call'
config/initializers/100-silence_logger.rb:29:in `call'
lib/middleware/enforce_hostname.rb:24:in `call'
lib/middleware/processing_request.rb:12:in `call'
lib/middleware/request_tracker.rb:385:in `call'

모든 사용자에게 문제가 발생하는 것 같지 않으므로, 일시적인 오류일 것이라고 기대했습니다. 하지만 패턴을 찾을 수 없습니다.

다음과 같은 작업을 수행할 수 있습니다:

 user=User.find_by_username 'xxx'
 DiscourseSubscriptions::Customer.find_by(user_id: user.id)

그리고 이것은 잘 작동합니다.

다음으로 어디를 봐야 할지 모르겠습니다.

무언가를 놓치고 있는 건지 모르겠지만, /s/<username>/subscriptions/는 플러그인에서 라우트가 아니지 않나요?

지금까지 로컬 환경과 프로덕션 사이트에서 /my/billing/subscriptions를 방문하면 /u/<username>/billing/subscriptions로 올바르게 리디렉션되며 500 오류가 발생하지 않습니다.

이 문제를 재현하는 방법에 대한 다른 단서가 있을까요?

도와주셔서 감사합니다!

해당 엔드포인트에서 데이터를 가져옵니다. 그리고 이 서버에서는 일부 사용자의 경우 500 오류가 발생하고 있습니다(스크린샷을 포함했어야 했는데, 그렇게 생각하네요). 꽤 오래전부터 발생하고 있었던 것 같나요? 저를 불러서 업그레이드를 진행하게 해 주셨고, 저는 업그레이드를 수행했습니다. 그러자 이 오류가 보고되었는데, 업그레이드로 인해 해결되기를 기대했던 것 같습니다(최소한 업그레이드 때문에 깨진 것은 아닌 것 같고요?).

전혀 없습니다. 제 추측으로는 과거에 어딘가에서 무언가가 발생하여, 지금은 어딘가에서 배열 대신 nil을 가져오는 것이 아닌가 싶습니다. 하지만 코드를 살펴봤는데, 배열에 접근하기 전에 nil을 검사하지 않는 곳이 어디인지 보이지가 않습니다.

이것은 해당 사이트에서만 발생하는 문제인 것 같습니다. 다른 사이트에서는 이런 현상이 나타나지 않나요? 500 에러를 반환해서는 안 되는 "버그"가 있는 것은 맞지만, 플랜 누락과 같은 어딘가에 “잘못된” 데이터가 존재할 가능성이 큽니다. 아마도 Stripe에서 데이터가 삭제되었지만 플러그인 데이터베이스에서는 업데이트되지 않았을 수 있습니다.

디버깅을 돕기 위해 다음 rails console 명령어를 실행해 주시겠어요?

Stripe.api_key = SiteSetting.discourse_subscriptions_secret_key
user = User.find_by(username: 'xxx')
customer = DiscourseSubscriptions::Customer.find_by(user_id: user.id)
subs = ::Stripe::Subscription.list(customer: stripe_customer_id, status: 'all')[:data]
subs.count # 사용자가 몇 개의 구독을 가지고 있는지 확인
subscription = subs.first # 이 부분을 변경하고 아래 줄들을 각 구독에 대해 실행
price_id = subscription[:items][:data].first[:price][:id]
plans = ::Stripe::Price.list(expand: ['data.product'], limit: 100)
plan = plans[:data].find { |p| p[:id] == price_id }
plan

plans 또는 plan 중 하나가 nil을 반환할 것 같지만, 이렇게 하면 문제가 어디에 있는지 좁혀 나가는 데 도움이 될 것입니다. 사용자가 몇 개의 구독을 가지고 있는지, 그리고 누락된 플랜이 있는지 알려주시겠어요?

제가 만들 코드 수정 사항은 에러가 발생하면 해당 사용자의 구독을 반환하지 않는 것일 수 있지만, 실제로 구독이 있는 경우라면 이는 문제를 근본적으로 해결하지 못합니다. 아마도 "구독은 발견되었지만 플랜 세부 정보를 불러오는 중 오류가 발생했습니다. 관리자에게 문의해 주세요."와 같은 오류 메시지를 반환하도록 할 것입니다.

좋아요. 감사합니다!

구독이 하나 있었습니다.

코드 수정 사항 하나:

subs = ::Stripe::Subscription.list(customer: customer.stripe_customer_id, status: 'all')[:data]

플랜이 100개 있습니다(아마 그 이상일 텐데요) – 이게 문제일까요? (limit: 1000으로 시도해 봤지만 아무 변화가 없었습니다. 아마도 Stripe API의 한계일 것 같습니다.)

그러니까 플랜이 100개를 초과하면 실패하는 건가요? 아, 그리고 실패하지 않는 사용자들은 처음 100개 안에 있는 플랜을 사용 중입니다.

discourse(prod)> plan = plans[:data].find { |p| p[:id] == price_id }
discourse(prod)>
=> nil

수정:

네. 이렇게 하면:

# 마지막 항목의 ID 가져오기
last_price_id = plans.data.last.id

# 다음 100개 가져오기
next_plans = ::Stripe::Price.list(
  expand: ['data.product'],
  limit: 100,
  starting_after: last_price_id
)

그런 다음

discourse(prod)> next_plans[:data].find { |p| p[:id] == price_id }

을 실행하면 원하는 항목을 찾을 수 있습니다.

다시 수정: next_plans.count == 8. 플랜 10개를 삭제하도록 제안했습니다.

다양한 정보를 제공해 주셔서 감사합니다. 도움이 됩니다.

네, 코드 수정 없이 문제를 해결하는 데는 이 방법이 효과적이겠네요. 오래된 플랜이 많이 있다면 좋은 해결책이 될 것 같습니다.

다시 이런 상황에 직면할 경우를 대비해 모든 데이터를 가져올 수 있도록 페이지네이션 기능도 추가하겠습니다.

해당 수정 사항은 다음과 같습니다: