Home > Software design >  Rails 6 grab results from Sidekiq Job - is it possible?
Rails 6 grab results from Sidekiq Job - is it possible?

Time:05-19

I've got Sidekiq job (SyncProductsWorker) which fires a class Imports::SynchronizeProducts responsible for a few external API calls.

module Imports
  class SyncProductsWorker
    include Sidekiq::Worker
    sidekiq_options queue: 'imports_sync'

    def perform(list)
      ::Imports::SynchronizeProducts.new(list).call
    end
  end
end

The Imports::SynchronizeProducts class gives an array of monads results with some comments e.g.

=> [Failure("999999 Product code is not valid"), Failure(" 8888889 Product code is not valid")]

I would like to catch these results to display them on FE. Is it possible to do so? If I do something like:

def perform(list)
  response = ::Imports::SynchronizeProducts.new(list).call
  response
end

And then inside of the controller:

def create
  response = ::Imports::SyncProductsWorker.perform_async(params[:product_codes])

  render json: { result: response, head: :ok }
end

I'll have some number as a result

=> "df3615e8efc56f8a062ba1c2"

CodePudding user response:

I don't believe what you want is possible.

https://github.com/mperham/sidekiq/issues/3532

The return value will be GC'd like any other unused data in a Ruby process. Jobs do not have a "result" in Sidekiq and Sidekiq does nothing with the value.

You would need some sort of model instead that keeps track of your background tasks. This is off the cuff but should give you an idea.

EG

# @attr result [Array]
# @attr status [String] Values of 'Pending', 'Error', 'Complete', etc..
class BackgroundTask < ActiveRecord
  attr_accessor :product_codes
  after_create :enqueue
  
  def enqueue
    ::Imports::SyncProductsWorker.perform_async(product_codes, self.id)
  end
end

def perform(list, id)
  response = ::Imports::SynchronizeProducts.new(list).call
  if (response.has_errors?)
    BackgroundTask.find(id).update(status: 'Error', result: response)
  else
    BackgroundTask.find(id).update(status: 'Complete', result: response)
  end
end

Then just use the BackgroundTask model for your frontend display.

  • Related