Problema com erro 500 nas assinaturas

Isto parece um Bug, mas não sei o que está acontecendo.

Vários usuários recebem um erro 500 ao tentar carregar /s/user/subscriptions/ (ao visitar /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/middleware/csp_script_nonce_injector.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'

Eu esperava que fosse um acaso, já que não parece estar com defeito para todos os usuários. No entanto, não consigo encontrar um padrão.

Eu consigo fazer isto:

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

e isso funciona.

Não tenho certeza para onde olhar a seguir.

1 curtida

Talvez eu esteja perdendo alguma coisa, mas /s/<username>/subscriptions/ não é uma rota no plugin, é?

Até agora, quando visito /my/billing/subscriptions localmente e em um site de produção, ele redireciona corretamente para /u/<username>/billing/subscriptions e eu não recebo um erro 500.

Alguma outra pista sobre como posso reproduzir isso?

Obrigado pela sua ajuda!

Ele puxa desse endpoint. E neste servidor, com alguns usuários, recebo um erro 500 (acho que deveria ter incluído uma captura de tela). Acho que isso está acontecendo há algum tempo? Eles me contrataram para fazer o upgrade, o que eu fiz, e então eles relataram esse erro, mas parece que eles esperavam que o upgrade fosse resolvê-lo (pelo menos o upgrade não o quebrou?).

Zero. Minha melhor suposição é que algo aconteceu em algum momento no passado e agora está recebendo um nil de algum lugar em vez de um array? Mas eu olhei o código e não vejo nenhum lugar que não esteja testando para nil antes de acessar um array.

1 curtida

Estou assumindo que é apenas para este site? Você não está vendo isso em outros sites? Sim, existe um “bug” onde não deveríamos retornar um 500, mas provavelmente há alguns dados “ruins” em algum lugar, como um plano ausente ou algo assim. Talvez tenha sido removido no Stripe e nunca tenha sido atualizado no banco de dados do plugin.

Você pode executar estes comandos do console Rails para me ajudar a depurar?

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 # observe quantos assinaturas eles têm
subscription = subs.first # mude isso e execute as linhas abaixo para cada sub
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

Estou pensando que ou plans ou plan retornarão nil, mas isso nos ajudará a identificar onde está o problema. Você poderia me dizer quantas assinaturas eles têm e se há planos ausentes para eles?

Provavelmente uma correção de código que farei é simplesmente não retornar nenhuma assinatura para esses usuários se houver um erro, mas se eles realmente tiverem uma assinatura, isso não resolverá o problema. Talvez eu faça com que retorne um erro dizendo algo como “uma assinatura foi encontrada, mas há um erro ao carregar os detalhes do plano para ela, entre em contato com um administrador para obter ajuda”.

Legal. Valeu!

Houve uma assinatura.

Uma correção no seu código:

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

Existem 100 planos (então provavelmente mais do que isso) - talvez esse seja o problema? (Tentei com limit: 1000, mas isso não mudou nada; acho que esse é um limite da API do Stripe?)

Então, talvez se houver >100 planos, falhe? Ah, e os usuários para os quais não está falhando, estão em planos que estão nos primeiros 100.

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

EDIT:

Sim. Se eu fizer isso:

# Pega o ID do último item
last_price_id = plans.data.last.id

# Pega os próximos 100
next_plans = ::Stripe::Price.list(
  expand: ['data.product'],
  limit: 100,
  starting_after: last_price_id
)

então

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

encontra o que procura.

EDIT NOVAMENTE: next_plans.count == 8. Eu sugeri que eles excluíssem 10 planos.

1 curtida

Obrigado por todas as informações, isso é útil.

Sim, isso resolveria o problema para uma correção sem código. Parece bom se eles tiverem muitos planos obsoletos.

Também adicionarei alguma paginação para que possamos pegá-los todos caso isso aconteça novamente.

1 curtida

Aqui está a correção para isso:

1 curtida

Este tópico foi automaticamente fechado após 4 dias. Novas respostas não são mais permitidas.