我的Rails应用程序中有一个控制器操作,通过短信和电子邮件与用户联系。由于我不打算进入的原因,在成功发送电子邮件之前需要完成短信。我原来有这样的事情:
控制器:
class MyController < ApplicationController
def contact_user
ContactUserWorker.perform_async(@user.id)
end
end
工人:
class ContactUserWorker
include Sidekiq::Worker
def perform(user_id)
SendUserTextWorker.perform_async(user_id)
SendUserEmailWorker.perform_async(user_id)
end
end
class SendUserTextWorker
include Sidekiq::Worker
def perform(user_id)
user = User.find(user_id)
user.send_text
end
end
class SendUserEmailWorker
include Sidekiq::Worker
def perform(user_id)
user = User.find(user_id)
user.send_email
end
end
这是不可靠的;有时电子邮件会失败,有时两者都会失败。我正在尝试确定perform_async
是否是导致问题的原因。 async
部分允许电子邮件在文本完成之前启动吗?我对perform_async
究竟是如何工作有点模糊,但这听起来像是一个合理的猜测。
首先,我将ContactUserWorker
重构为:
class ContactUserWorker
include Sidekiq::Worker
def perform(user_id)
user = User.find(user_id)
User.send_text
SendUserEmailWorker.perform_async(user_id)
end
end
最后,我只是将呼叫从send_text
移出工作人员并进入控制器:
class MyController < ApplicationController
def contact_user
@user.send_text
SendUserEmailWorker.perform_async(@user.id)
end
end
这是真实代码的简化版本,但这是它的要点。它现在看起来工作正常,但我仍然想知道这个问题是否与Sidekiq相关或是否还有其他问题。
我很好奇,如果我使用perform
而不是perform_async
用于除电子邮件调用之外的所有通话,我的原始结构是否会有效。像这样:
class MyController < ApplicationController
def contact_user
ContactUserWorker.perform(@user.id)
end
end
class ContactUserWorker
include Sidekiq::Worker
def perform(user_id)
SendUserTextWorker.perform(user_id)
SendUserEmailWorker.perform_async(user_id)
end
end
答案 0 :(得分:1)
我很好奇我的原始结构是否会起作用,如果我使用的是perform而不是perform_async用于除电子邮件调用之外的所有通话
它会有。但这并不是你实际上的东西。你真正想要的是:
class MyController < ApplicationController
def contact_user
ContactUserWorker.perform_async(@user.id)
end
end
class ContactUserWorker
include Sidekiq::Worker
attr_reader :user_id
def perform(user_id)
@user_id = user_id
user.send_text
user.send_email
end
def user
@user ||= User.find user_id
end
端
问题确实是执行异步部分。它通过单独的sidekiq守护进程安排在后台执行的两个任务。我猜你的sidekiq配置为同时执行作业。在第一个版本中,您首先安排ContactUserWorker
在当前rails请求之外的后台执行该作业。由于这个工作人员稍后开始工作,它依次启动两个单独的延迟工作,然后并行运行,因此无法确定两者中的哪一个先执行/完成。
我不会通过发送文字知道你的意思,但发送电子邮件是一个阻止过程,因此在后台执行此操作是个好主意,因为它会阻止完整的rails过程否则,直到电子邮件发送(在典型的独角兽/乘客多进程部署)。而且你实际上想要按顺序执行这两个任务并作为一个原子操作,它完全没问题,由一个sidekiq工作/工作人员执行它们。
您也不必检查send_text是否成功。如果Sidekiq的任何部分失败并且异常
,它将重试整个作业答案 1 :(得分:1)
如果电子邮件只能在发送短信后发送,请在成功完成发送文本后发送电子邮件。
class ContactUserWorker
include Sidekiq::Worker
def perform(user_id)
SendUserTextWorker.perform_async(user_id)
end
end
class SendUserTextWorker
include Sidekiq::Worker
def perform(user_id)
user = User.find(user_id)
text_sent = user.send_text
SendUserEmailWorker.perform_async(user_id) if text_sent
end
end
class SendUserEmailWorker
include Sidekiq::Worker
def perform(user_id)
user = User.find(user_id)
user.send_email
end
end
在user.send_text中,您需要处理文本或电子邮件均未发送的事实。