Active Job – Handling Background Job in Rails

Tram Ho

1. Place the problem

Suppose you want to send an email to the users after registering for an account to confirm your account on your Sample app page (the website that most of the Rails classmates will do through). If there are thousands of users registering at the same time, you will have to simultaneously send thousands of emails with account authentication content, this will lead to a response between the server and the client being affected. enjoy significantly.

=> We need to find a solution how to handle the tasks separately, the Background Job will help us in performing the tasks in a separate thread and not affect the experience of the user whose jobs will be processed. => In this article, I will handle sending mail to the Background Job

2. What is Background Job?

Background job – ” background jobs “: are jobs or tasks that are processed out of the usual request – response flow in web applications.

Normally, the website receives a request from the user and returns a response, but the Background job is a little different => Still from a request to the Website, but requires longer execution time than usual (can be thought It seems that these requests cannot be processed immediately), we will need to use the Background job , move that complicated processing into the Job, it will process asynchronously on a separate thread, return response to the user.

For example

We have a request from the user to update their new home town information:

As you can see, the time from the time the user submits the form until the server returns the user page and the notification is successful will take 3.7 seconds.

When we use the Background job: the process we mentioned above only takes 0.3 seconds, processes like refresh cache , send maild , send noti , recommend new friends will be processed by Background job in a separate thread, the results will still be returned as desired by the user

3. How does Rails handle Backgound Job?

There are several ways to handle Background Job for your Rails application:

  1. Use Active job
  2. Use Gem Sidekiq
  3. Use a Gem Delayed job
  4. Use Gem Resque

By default, Rails provides us Active job (A framework for handling Background job that we don’t need to install anything more about built-in queue process (built-in queue).

Unfortunately, the queue processes are stored in RAM, so if the server is shut down, the jobs that are not in progress or in progress will be lost, which can negatively affect our users and services. It is only suitable for small applications or unimportant jobs.

However, most large applications didn’t want this to happen, so they used 3rd-party adapter like Sidekiq, Delayed_Job, Resque (which uses Redis to store queues, and has its own mechanisms for handling jobs when Server crashes and reboots will not lose jobs)

In this article, I mainly learn about Active jobs to handle Background Job, the other 3 ways you can learn more in the articles or on its doc to read.

I have also used Sidekiq (the other 2 have not): in addition to the perfect job handling, it also has some differences with other gems: Sidekiq uses multithreading and Redis to handle many jobs. also .Sidekiq and Rescue have a dashboard for managing jobs, while Active job and Delayed_job don’t (Delayed_job can install a gem to use the dashboard). In addition, passing parameters of Sidekiq will be different from Active job, I will show below

To handle jobs using adapters such as Sidekiq, Delayed Job, Rescue, we can configure as follows:

  • Change queue_adapter in the application.rb file

  • Configure it in the file …_ job.rb

  • In addition, if you want to more explicitly manage the queue that the job will run, you can use the #set method as follows:

4. Active Job – Handling Background Job in Rails

First, I will handle the problem of putting the email to activate user accounts in the job

First we must create a job that you want using the rails g job SendMail command

The send_mail_job.rb file will look like this:

By default, Active job uses queue_as :default which means the adapter uses :async to save the job, in addition there is another adapter :inline , to use it, we have to configure at application.rb as follows:

=> When using adapter :inline , the job will be executed immediately in the main thread, it is no different from not using the Background job , so I think you should not use it.

=> So what about the default Active job adapter :async : Job will execute in another thread group, suitable for dev / test environment because it does not need external infrastructure, but it is not suitable in environment production field, as it removes any pending jobs on reboot. If the jobs share the same thread group, the jobs behind have to wait for the jobs to finish running (so if jobs are waiting and the server is reset, it will be lost.

Note : To overcome the above disadvantages, you can configure queue_adapter = :sidekiq , of course you must install gem sidekiq , turn on sidekiq’s server and use it, sure your job will not be lost when restarting the server, I have tried it.

We can configure the number of threads: async works like this:

With Active job, you can pass as many parameters as you want, maybe an entire object, namely:

For Sidekiq: the arguments passed must be simple JSON types such as string, integer, boolean, float, null (nil), hash, array.

After a bit of rambling, solve the problem of sending mail), just do the following:

That’s it, here’s my extra bonus

4.1. Job calls

Execute the job as soon as the queue is empty:

Do it after a period of time:

Do the job at noon tomorrow:

Note: Besides perform_later also have perform_now , when you use perform_now , the time you set to perform the job becomes meaningless.

4.2. Callbacks of Active job

Active Job provides callbacks to trigger logic in the life cycle of a job. Works similarly to other callbacks in the Rails model as follows:

=> is called before, during, and after queuing the job

=> is called before, during, and after the job is executed

4.3. Handling exceptions

During the job execution it is not possible to always be smooth, Active Job provides us with ways to catch exceptions raised during job execution:

  1. Handle exception in perform function body

  1. discard_on (* exceptions): Eliminate the job that you do not want it to retry when raising exceptions, which is useful when the record has been deleted, for example.

  1. retry_on (* exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil)Schedule the job to re-run when the job raises the exception, if the exception increases to exceed the number of attempts you set => can have your own retry mechanism for exceptions or put it in queue to check
  • : wait – re-queues the job for a pending period
  • : attempts – to re-enter the queue to be processed many times
  • : queue – Put the job in another queue
  • : priority – Re-arrange the job according to the priority

5. References

The article is quite long, but that is what I have learned about Active Job and hope that some part helps you have an overview of the Background job and the operating mechanism of Active Job . Thank you for reading here

Guide Active job:

https://guides.rubyonrails.org/active_job_basics.html

https://api.rubyonrails.org/classes/ActiveJob/Exceptions/ClassMethods.html

Share the news now

Source : Viblo