How to make simple background jobs processing in Rails with Sucker Punch
Writing jobs, testing, pros and cons of this approach.
Sucker Punch — a single-process Ruby asynchronous processing library that runs with your existing app’s process.
Gem is built on top of concurrent-ruby and have no dependencies with any data storage, what is both an advantage and a disadvantage.
Running in the application process really simplifies the deployment process, but If the web processes are restarted with jobs remaining in the queue, they will be lost. Also, since all state persistence is in memory, Sucker Punch can operate extremely fast on small tasks. But if the application implies a large number background jobs, Sucker Punch turns out to be the wrong decision, because you’ll need to write your own logic of monitoring/restarting jobs.
Add this line to your application’s Gemfile:
And then execute:
If you want to use Sucker Punch with Active Job, you can to add it as an adapter to
config/application.rb into Rails app.
Each job should be a separate Ruby class that includes
SuckerPunch::Job and defines
To run synchronous execution initialize the instance class and call method
perform on it.
This will return the result of code execution in
Asynchronous execution returns
true and continue execution in the thread.
The default number of workers (threads) running against your job is 2. This can be configured using the class method
Sucker Punch provides an interface for delaying jobs. But remember that schedule will clear after restarting application process.
In the example above
perform will be executed 60 seconds later.
To avoid problems such as cleared transactions using something like Database Cleaner, because the job class is running in a different thread and the Transaction operates on another thread so it can clear data before the job will be finished, you should disable transactional fixtures.
Requiring this library causes your jobs to run everything inline. So a call to the following will actually be synchronously:
For example, we have some job, which triggers service object which calculates statistics:
We should tag the spec as a
You can customize how to handle uncaught exceptions that are raised by your jobs. For example, with third-party service like Sentry with raven-ruby gem.
If Sucker Punch is being used within a Rails application, Sucker Punch’s logger is set to
Rails.logger by default.
If your application is designed for high load, it will be difficult to implement horizontal scale-up with Sucker Punch. In this case, you will need a tool that will enqueue jobs in the storage (e.g. Redis). For larger applications, I recommend using Sidekiq, Resque or Delayed::Job. But they all have a similar interface, and you do not have to significantly rewrite the code to switch from Sucker Punch to one of the alternatives.