我想要两件事:
a) 我希望仅当 API 调用成功时才能够在数据库中保存一条记录
b) 我只想在数据库记录成功保存时执行 API 调用
目标是使存储在本地(在数据库中)的数据与 Stripe 上的数据保持一致。
@payment = Payment.new(...)
begin
Payment.transaction do
@payment.save!
stripe_customer = Stripe::Customer.retrieve(manager.customer_id)
charge = Stripe::Charge.create(
amount: @plan.amount_in_cents,
currency: 'usd',
customer: stripe_customer.id
)
end
# https://stripe.com/docs/api#errors
rescue Stripe::CardError, Stripe::InvalidRequestError, Stripe::APIError => error
@payment.errors.add :base, 'There was a problem processing your credit card. Please try again.'
render :new
rescue => error
render :new
else
redirect_to dashboard_root_path, notice: 'Thank you. Your payment is being processed.'
end
下面的代码会起作用,因为如果记录(第 5 行)不保存,则其余代码不会执行。
但是,如果我需要在 API 调用后保存 @payment
对象怎么办,因为我需要为 @payment
对象分配来自 API 结果的值。举个例子:
@payment = Payment.new(...)
begin
Payment.transaction do
stripe_customer = Stripe::Customer.retrieve(manager.customer_id)
charge = Stripe::Charge.create(
amount: @plan.amount_in_cents,
currency: 'usd',
customer: stripe_customer.id
)
@payment.payment_id = charge[:id]
@payment.activated_at = Time.now.utc
@payment.save!
end
# https://stripe.com/docs/api#errors
rescue Stripe::CardError, Stripe::InvalidRequestError, Stripe::APIError => error
@payment.errors.add :base, 'There was a problem processing your credit card. Please try again.'
render :new
rescue => error
render :new
else
redirect_to dashboard_root_path, notice: 'Thank you. Your payment is being processed.'
end
您注意到 @payment.save!
发生在 API 调用之后。这可能是个问题,因为 API 调用在数据库尝试保存记录之前就已运行。这可能意味着 API 调用成功,但数据库提交失败。
对这个场景有什么想法/建议吗?
最佳答案
你不能同时执行 API => DB 和 DB => API(听起来像是一个无限执行的条件),至少我无法想象你是如何实现这个工作流程的。我了解您的数据一致性需求,因此我建议:
- 检查记录是否有效
@payment.valid?
(可能使用像valid_without_payment?
这样的自定义方法) - 运行 api 调用
- 仅当 api 调用成功时才保存记录(使用
payment_id
)
或者:
- 不带
payment_id
保存记录 - 运行 api 调用
- 如果调用成功,用
payment_id
更新记录(api响应) - 定期(cron)运行任务(脚本)以检查不一致的实例(
where(payment_id: nil)
)并删除它
我认为这两种选择都可以接受,您的数据将保持一致。
关于ruby-on-rails - 如果 API 调用失败,我该如何回滚事务,反之亦然?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21919553/