Skip to content

Rodrigo Urubatan – About Code

Helping ruby developers to use the best tools for each job so they can solve hard problems, with less bugs and have more free time.

Menu
  • Home
  • My last presentations
  • About
  • Privacy Policy
Menu

ActiveJob and declarative exception handling in your background workers

Posted on 2018-08-10 by Rodrigo Urubatan

Rails 5.2.1 was recently released, and released and it brought some improvements to ActiveJob (most of it was already in 5.1 really, the only thing added on 5.2 was the callback on discard_on), but lets keep in the subject here 😀

Recently I published a very basic post about ActiveJob, and these declarative exception handling tips will help to improve a lot your worker’s code!

For example, usually if one exception is rised during the job execution, the job will retry again later, but you might have some business exception that you wanna ignore and not try again, maybe something that says that your job is invalid.

I had one of these cases, some news that could be scheduled for delivery bug the reporter decided to delete it, so if the news was not found in the database the job should just ignore it, but when I implemented this I didn’t had this pretty helper, so I added a begin/rescue block to return and do nothing in the job, that code is ridiculous, but it was what I had available, it would be a lot better if I could just add something like this:

class NewsDeliveryJob < ActiveJob::Base
discard_on(ActiveRecord::RecordNotFound)
def perform(args)
#...
end
end

This is a lot prettier than my version, because you can clearly see that the job should be discarded if a record is not found, and it is better than that, imagine that you want to discard the job, but also log why you did it, you can just pass a block to the discard_on method, like this:

class NewsDeliveryJob < ActiveJob::Base
  discard_on(ActiveRecord::RecordNotFound) do|job, exception|
    logger.error(exception)
    logger.log("job not retrying due to exception"
  end
  def perform(args)
    #...
  end
end

You can also access the job properties in that blog, log what is not being retried, the sky is the limit!

You can also change how long the job will wait before retrying and how many times it will retry depending on your business criteria, to do that you’ll use the retry_on method, that will also receive an exception as he first parameter, and optionally a ‘wait’ and a ‘attempts’ options as you can see in the sample bellow:

class NewsDeliveryJob < ActiveJob::Base 
  retry_on MyAppException # defaults to 3s wait, 5 attempts 
  retry_on BusinessException, wait: ->(executions) { executions * 2 }
  retry_on ActiveRecord::Deadlocked, wait: 5.seconds, attempts: 3
  retry_on Net::OpenTimeout, wait: :exponentially_longer, attempts: 10
  discard_on ActiveJob::DeserializationError
  discard_on(ActiveRecord::RecordNotFound) do |job, exception|
    log.error(exception)
    log.error(job.inspect)
  end
  def perform(*args)
    # do your thing here
  end
end

As you can see the configurations to retry can be really flexible (I cannot think right now in a job needing it all at once).

And another cool thing from rails 5.1 is that you can choose what job will be used to deliver your emails, of course you can just use the rails default email delivery job, but if you want to do some extra verification in your email before delivery, you can just set the delivery_job property in your mailer as you can see bellow:

class MyMailer < ApplicationMailer
  self.delivery_job = MyMailDeliveryJob
  ...
end

After that, when you execute MyMailer.mail_method(paras).delivery_later, your MyMailDeliveryJob will be executed to deliver that email instead of the default one, this way you can even choose what queue name to use instead of the default ‘mailers’.

I think those were all the cool new stuff on the ActiveJob package, and I think those new features will help me a lot in the next project 😀

Please leave a comment if you have any question about this post, or if you want me to write about any specific subject in the future.

Related

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent posts

  • Why Embrace Nesting in Ruby Modules?
  • An easy way to have a local “Github Copilot” for free
  • SPA without touching Javascript – The magic of Ruby on rails and Hotwire
  • I see Dead Jobs everywhere (sidekiq DeadSet)
  • Quick tips that help: rails notes

Arquives

  • May 2024
  • April 2024
  • February 2023
  • January 2023
  • December 2022
  • June 2021
  • March 2020
  • January 2020
  • July 2019
  • June 2019
  • May 2019
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • February 2018
  • January 2018
  • November 2017
  • August 2015
  • August 2014
  • July 2014
  • August 2007

Categories

  • AI
  • articles
  • cfp
  • firebase
  • gems
  • git
  • opinion
  • presentations
  • projects
  • rails6
  • ruby
  • Sem categoria
  • server-api
  • tutorials
  • Uncategorized
© 2025 Rodrigo Urubatan – About Code | Powered by Minimalist Blog WordPress Theme