在實務中,常常會有花很長執行時間、或需要排程的邏輯,這時候便會需要進行非同步處理。
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)
參數盡量傳簡單的 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 主要缺點有兩個:
下一篇會介紹如何對 Boxenn::UseCase
進行測試。