在实务中,常常会有花很长执行时间、或需要排程的逻辑,这时候便会需要进行非同步处理。
在 Boxenn Use Case 上扩充 sidekiq worker
sidekiq worker 的介面需要 perform
这个 method,而对於 Boxenn::UseCase
来说,他原本对外就只有 call
这个 public method,因此扩充的方法很简单,只需要额外定义 perform
让他呼叫 call
就可以了。
module Worker
def self.included(base)
base.send(:include, Sidekiq::Worker)
end
def perform(*params)
result = if params.empty?
call
else
call(serialize(*params))
end
return if result.success?
# error handle
message = Array(result.failure).map(&:to_s).join(', ')
Rollbar.error(message, trace: result.trace)
raise StandardError, message
end
private
def serialize(params)
params.transform_keys(&:to_sym)
end
end
使用方法
只需要在原本的 Use Case 多 include 上面所写的 Worker
就可以使用了。
class YourWorker < Boxenn::UseCase # inherit Boxenn::Usecase
include Worker # include Worker for asynchronize purpose
sidekiq_options queue: :default # setting sidekiq options
def steps(params1:, params2:)
result = action1(params1: params1, params2: params2)
Success(result)
end
private
def action1(params1:, params2:)
# DO SOMETHING
end
end
# calling use case asynchronize
YourWorker.perform_async(params1: params1, params2: params2)
# calling use case synchronous
YourWorker.new.call(params1: params1, params2: params2)
Sidekiq Best Practice
-
参数尽量传简单的 identifier (原生 ruby type),而不是整个 object。
Sidekiq 会把参数会先转为 json 存进 redis,等到要执行时再序列化为 ruby object,因此如果原本的参数不是原生型态,不但需要更多时间序列化,甚至有可能出现序列化错误的问题。
# BAD user = User.find(user_id) SomeWorker.perform_async(user) # GOOD SomeWorker.perform_async(user_id)
-
用 perform_async 代替 delay extension,delay extension 主要缺点有两个:
- 传的参数太复杂时有可能造成 redis timeout,因为 sidekiq 是用 yml 来序列化参数,传太复杂的 ruby object 会让 payload 很大。
- 会在 class 上额外加 method。
下一篇会介绍如何对 Boxenn::UseCase
进行测试。