Rails - 将对象作为参数传递而不进行序列化

Rails - Pass object as argument without serializing

我有一个控制器,我必须从中将对象实例作为参数传递给 Sidekiq 的 Worker class。

我的控制器随叫随到WegWorker.synchronize(@service)

class Api::V2::Events::WegSessionsController < Api::V2::Events::ApplicationController
  before_action :load_service

  def synchronize
    @service.keep_cancelled = params[:keep_cancelled].to_b
    if @service.valid_connection?
      WegWorker.perform_async(@service)
      render json: {
        status: :ok,
        message: @service.message
      }, status: :ok
    else
      render json: {
        status: :unprocessable_entity,
        errors: @event.errors.full_messages
      }, status: :ok
    end
  end
    .. some code with service object instantiation
end

我的工人class

class WegWorker < ::CarrierWave::Workers::ProcessAsset
  include Sidekiq::Worker 
  sidekiq_options retry: false

  def perform(service)

    service.synchronize
  end
end

但我目前收到的错误是

WARN: NoMethodError: undefined method `synchronize' for "#<WegService:0x0000000013f9abb0>":String

如何在不序列化对象的情况下将对象传递给工作人员?

您正在用这个 WegWorker.perform_async(@service) 排队一个复杂的 Ruby 对象。这不会被正确序列化,您最终会得到一个类似于 "#<WegService:0x0000000013f9abb0>" 的字符串。虽然反序列化 Sidekiq 不会像您期望的那样将其转换为原始 class。

您应该只对简单对象进行排队。因此,您可以将标识符推送到异步作业并在 perform 方法中自己重新实例化服务。

此外,我的建议是阅读 Sidekiq 文档。它们非常小,您可以避免此类错误。 Relevant link 本节。

Sidekiq 作业只能使用 simple parameters,如字符串、数字等。要解决此问题,推荐的方法是在 WegService 上定义以下方法:

class WegService
  def self.from_params(params)
    new(...) #rehydrate your service using params
  end

  def to_params
    [43, 'foo', 'bar'] # pickle your service
  end

  # ...
end

然后,你会像这样排队:

WegWorker.perform_async(@service.to_params)

而工人将有:

def perform(params)
  WebService.from_params(params).synchronize
end