订阅时出现500错误的问题

这看起来像个 Bug,但我不知道是怎么回事。

很多用户在访问 /my/billing/subscriptions 时会遇到 500 错误,无法加载 /s/user/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'

我希望这只是个巧合,因为它似乎并非影响所有用户。我找不到任何规律。

我可以这样做:

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

这是可以正常工作的。

我不确定接下来该看哪里。

1 个赞

也许我遗漏了什么,但是 /s/<username>/subscriptions/ 并不是插件中的路由,对吧?

到目前为止,我在本地和生产站点上访问 /my/billing/subscriptions 时,它都会正确重定向到 /u/<username>/billing/subscriptions,并且我没有收到 500 错误。

还有其他关于我如何重现此问题的线索吗?

感谢您的帮助!

它会从该端点拉取。在此服务器上,对于某些用户,我会收到 500 错误(我认为我应该附上截图)。我认为这种情况已经发生了一段时间了?他们让我加入升级,我照做了,然后他们报告了这个错误,但似乎他们希望升级能够解决它(至少升级没有破坏它?)。

零。我最好的猜测是,过去某个时候发生了某些事情,现在它从某个地方得到了一个 nil 而不是一个数组?但我已经查看了代码,没有看到任何地方在访问数组之前没有检查 nil

1 个赞

我猜这只是针对这个网站?你在其他网站上没有看到这个吗?是的,有一个“bug”,我们不应该返回 500,但可能有一些“坏”数据,比如缺少计划或类似的东西。也许它在 Stripe 中被删除了,但从未在插件数据库中更新。

你能运行这些 rails 控制台命令来帮助我调试吗?

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

我猜计划或 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 个计划。

1 个赞

感谢所有信息,这很有帮助。

是的,这可以解决非代码修复的问题。如果他们有很多过时的计划,听起来不错。

我也会添加一些分页,以便我们以后遇到这种情况时可以全部获取。

1 个赞

这是修复方法:

1 个赞

此主题已在 4 天后自动关闭。不再允许回复。