Rails how to tell if a sidekiq worker is done with perform_async
Checkout the following extension gem to sidekiq: https://github.com/utgarda/sidekiq-status/blob/master/README.md
This is from the read me:
job_id = MyJob.perform_async(*args)
data = Sidekiq::Status::get_all job_id
data # => {status: 'complete', update_time: 1360006573, vino: 'veritas'}
Sidekiq::Status::get job_id, :vino #=> 'veritas'
Sidekiq::Status::at job_id #=> 5
Sidekiq::Status::total job_id #=> 100
Sidekiq::Status::message job_id #=> "Almost done"
What happends when a perform_async is called but sidekiq is not running?
Simple answer: it is not done. It will be done later
As the name it self is saying it puts it in a que
. When you turn on sidekiq
it will read all data from que
and execute all tasks.
But for this to work you need to have Redis
working. Redis
is responsible for saving data in a que, it is a kind of memory. Without Redis
you would get an error.
What is perform_async in sidekiq
perform_async
- a method that push your job with your params in the async queue (create a record in your async backend, Redis by default), to allow Sidekiq catch and perform it on the order of queue
Source: https://github.com/mperham/sidekiq/blob/e2f92e8279d1947aa45eb86acc73f9ebe7a92c9c/lib/sidekiq/worker.rb#L6-L43
Sidekiq: perform_async and order-dependent operations
If the email can only be sent after the text message has been sent, then send the email after successful completion of sending the text.
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
In user.send_text you need to handle the fact that neither the text or the email has been sent. perform_async not working in sidekiq
Well I found your bug, in your boot.rb
file you have this line:
require 'sidekiq/testing/inline' if RACK_ENV == 'development'
This bit of code, uses Sidekiq's Testing framework which bypasses redis and runs it almost as if it's a ruby class (ie it doesn't ever get queued on redis). Remove that line and only use it in your test suite (if you need it).You'll also need to remove that pid file from your YML file, you don't need that and if you do, it's probably only for production. My 2cents - remove it.
Once you do that, you're good to go:
Here's your rackup with a get request to /hardworker:
[2015-06-07 07:54:25] INFO WEBrick 1.3.1
[2015-06-07 07:54:25] INFO ruby 2.2.2 (2015-04-13) [x86_64-darwin14]
[2015-06-07 07:54:25] INFO WEBrick::HTTPServer#start: pid=74128 port=9292
INFO - I'll call HardWorker
INFO - HardWorker was called
DEBUG - GET (0.0131s) /hardworker - 200 OK
::1 - - [07/Jun/2015:07:55:32 -0400] "GET /hardworker HTTP/1.1" 200 46 0.0291
Here's sidekiq processing that job in the background:─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
ss
sss sss ss
s sss s ssss sss ____ _ _ _ _
s sssss ssss / ___|(_) __| | ___| | _(_) __ _
s sss \___ \| |/ _` |/ _ \ |/ / |/ _` |
s sssss s ___) | | (_| | __/ <| | (_| |
ss s s |____/|_|\__,_|\___|_|\_\_|\__, |
s s s |_|
s s
sss
sss
INFO - Running in ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]
INFO - See LICENSE and the LGPL-3.0 for licensing details.
INFO - Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org/pro
INFO - Starting processing, hit Ctrl-C to stop
DEBUG -
INFO -
INFO - Doing hard work
INFO - redis location: [127.0.0.1:6379]
INFO - connected clients: [3]
INFO - hard work was done
INFO -
Rails 6 grab results from Sidekiq Job - is it possible?
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. Test Sidekiq job that changes value of object
To test that your worker is doing the work you intend it to do - test perform
rather than perform_async
:
describe OrderProcessorWorker do
it 'changes order status' do
subject.perform(order_id)
expect(Order.find(id: order_id).status).to eq 'processed'
end
end
Related Topics
Rails Redirecting Invalid Route to Root
Difference Between @@ and @ in Ruby
How Does String.Unpack Work in Ruby
How to Test Strong Params with Rspec
Should I Delete Migration After Rollback
How Does Ruby's Sort Method Work with The Combined Comparison (Spaceship) Operator
Rails How to Create Data Schema Seed Data
How to Use The "Self" Keyword in Rails
How to Remove Backslashes from a JSON String
Case Insensitive Search in Rails
Sinatra on Nginx Configuration - What's Wrong
Ruby Require 'File' Doesn't Work But Require './File' Does. Why
How to Handle Serialized Edit Fields in an Active Admin Resource
Why Can't Net::Ftp Connect to Server
Paperclip: Integration with Mailboxer Gem
Explanation of Ruby Code for Building Trie Data Structures
Dbi::Interfaceerror: Could Not Load Driver (Uninitialized Constant MySQL error)
How to Convert Ruby Formatted JSON String to JSON Hash in Ruby