如何延迟 Rails 控制器操作,直到 Stripe 的 webhook 成功?

Posted

技术标签:

【中文标题】如何延迟 Rails 控制器操作,直到 Stripe 的 webhook 成功?【英文标题】:How to delay Rails controller action until Stripe's webhook has succeeded? 【发布时间】:2021-09-04 09:00:20 【问题描述】:

在我的 Stripe 实现中,用户可以像这样添加新的 payment methods:

class PaymentMethodsController < ApplicationController

  def index
    @payment_methods = current_account.payment_methods
  end

  def new
    setup_intent = Stripe::SetupIntent.create(
      :payment_method_types => ['card', 'sepa_debit'],
      :customer => current_account.stripe_id
    )
    @client_secret = setup_intent.client_secret
  end

  def create
    flash[:success] = "Payment method created."
    redirect_to payment_methods_path
  end

end

(不过,确切的实现在这里并不重要。)

我还将每个用户的付款方式的副本存储在我的数据库中,以便能够在我的控制器的index 视图中向用户显示它们。

现在的问题是我正在使用 Stripe 的 webhook 创建这些数据库条目,并且这些 webhook 通常需要几秒钟才能访问我的应用程序。

因此,当我在用户创建新付款方式后将其重定向到付款方式列表 (payment_methods_path) 时,最新的付款方式通常在那里不可见,这非常令人困惑。只有当用户重新加载他们的页面时,新条目才会可见(因为届时 Stripe 的 webhook 会成功)。

有没有办法延迟 Rails 控制器操作,直到某个 webhook 成功,甚至延迟固定的秒数(例如 5)?

我的订阅也面临同样的问题,我的订阅只有在 webhook 成功后才在本地创建。在此之前,我的用户仍处于免费计划中几秒钟,这不是一个大规模问题,但我的许多用户仍然感到非常困惑。

解决这个问题的最佳方法是什么?

【问题讨论】:

【参考方案1】:

有没有办法延迟 Rails 控制器操作,直到某个 webhook 成功,甚至延迟固定的秒数(例如 5)?

是的。 但这是个坏主意。您可以通过简单地告诉服务器sleep 来延迟发送响应。但是,这不是您想要的,因为它可能会导致客户端超时连接并会占用您的网络服务器上的线程。

这个问题的经典解决方案是polling 或long polling,您使用javascript 发送重复的XHR 请求来唠叨服务器,直到您等待的任何内容完成。长轮询消除了建立新连接所涉及的成本,但需要服务器允许大量同时连接。

现在您可以使用WebSockets,它允许双工连接。这在 Rails 中以ActionCable 的形式提供了内置支持。 server-sent-events 也是一种替代方案,但需要您在更大程度上自己滚动。

【讨论】:

【参考方案2】:

您还可以使 webhook 和返回 URL 中的代码具有幂等性;即,任何一个人都可以创造这个东西。这样,哪个先发生都无所谓,既然你有 webhook,它肯定会最终发生。

【讨论】:

以上是关于如何延迟 Rails 控制器操作,直到 Stripe 的 webhook 成功?的主要内容,如果未能解决你的问题,请参考以下文章

Rails/Rspec:测试延迟作业邮件

如何在常规 Ruby 代码(非 Rails)中使用 strip_tags?

如何延迟加载反应应用程序直到触发操作?

如何将延迟的ajax数据获取到rails视图

如何在 Ruby on Rails 中完成延迟作业后执行 ajax 回调?

在 Rails 中清理输入 XSS 和 HTML 输入