In Rails 4.2 check if the job is running

I am using Rails 4.2 and delayed_job 4.0.6 as an ActiveJob backend.

I have a job that I would like to allow only in line. The work in question takes a minute to run. It is marked with a model callback. The callback will be triggered much more often than the task can be completed. The task does not need to be queued more than once in the future.

Here is some pseudo code for what I'm trying to execute.

# app/jobs/refresh_account_cache_job.rb class RefreshAccountCacheJob < ActiveJob::Base def before_enqueue skip if job_already_enqueued end def perform Account.write_to_cache end def job_already_enqueued # ? end end 

If the job instance is started when it is called again, it should still remain in the queue in the future. I am looking for a way for a task to be run for future launch at most 1 time.

I assume that the answer should be specific to delayed_job, but if it can be generalized to ActiveJob, it will be even better.

+5
source share
3 answers

This may not be an exact fit, but it should point in the right direction:

 def self.up create_table :delayed_jobs, :force => true do |table| table.integer :priority, :default => 0, :null => false table.integer :attempts, :default => 0, :null => false table.text :handler, :null => false table.text :last_error table.datetime :run_at table.datetime :locked_at table.datetime :failed_at table.string :locked_by table.string :queue table.timestamps end 

So, you can add a status column to this table, then run such a query to capture the task and check its status before doing anything else.

Delayed::Job.where(queue: '<YOUR QUEUE>').where(id: params[:id]).status

How would you establish a status, you ask? Well, use the hook of success in deferred missions. It would look something like this:

 def success(job) update_status('success') end private def update_status(status) job = Job.find job_id job.status = status job.save! end 

Hope this helps!

+2
source

I am posting what I finished by becoming a response in order to get a response to it. This is just a possible solution that I am testing.

In the job, I check the Delayed :: Job list to see if the current handler is present. If I missed the task.

 # queue_job.rb class EnqueueJob < ActiveJob::Base queue_as :default def already_enqueued? Delayed::Job.all.any? do |job| job.handler.include?("EnqueueJobHandler") end end def perform unless already_enqueued? # do stuff end end end 

So far, this has prevented work from overlapping the queue. The downside is that I don’t know that I keep the cache as relevant as I want.

+1
source

This might be too simplistic, but why not just add a class variable, say @@running , set it true to before_enqueue and clear it at the end of the job?

Then you can simply check this variable and skip it if it is set.

0
source

Source: https://habr.com/ru/post/1213535/


All Articles