rake check if already running
Asked Answered
B

5

9

Is it possible somehow to execute rake task only if it is not running already, I want to use cron for executing some rake tasks but rake task shouldn't start if previous call is not finished Thanks

Burmeister answered 6/9, 2011 at 13:54 Comment(0)
G
13

I use lockrun to prevent cron tasks from running multiple times (this only works when invoking the command through the same lockrun invocation, so if you need to protect from various invocation paths, then you'll need to look for other methods).

In your crontab, you invoke it like this:

*/5 * * * * /usr/local/bin/lockrun --lockfile=/var/run/this_task.lockrun -- cd /my/path && RAILS_ENV=production bundle exec rake this:task
Groundmass answered 14/9, 2011 at 2:36 Comment(2)
There's also flock (frequently in /usr/bin/flock) on some systems - the question didn't specify the OS.Yasmineyasu
Problem with flock is you can't run a command with more than one argument, so rake task_name is two arguments and therefore fails.Pogonia
P
10

Also, you can use a lockfile, but handle it in the task:

def lockfile
  # Assuming you're running Rails
  Rails.root.join('tmp', 'pids', 'leads_task.lock')
end

def running!
  `touch #{lockfile}`
end

def done!
  `rm #{lockfile}`
end

def running?
  File.exists?(lockfile)
end

task :long_running do
  unless running?
    running!
    # long running stuff
    done!
  end
end

This probably could be extracted into some kind of module, but you get the idea.

Personnel answered 21/10, 2011 at 15:25 Comment(0)
R
5

The general non-rake specific solution to this is to use a pid file as a lock. You would wrap the rake task in a script that creates this file when it runs rake, removes it when rake finishes running, and checks for it before beginning.

Not sure if rake has something built in, I don't know of anything.

Retuse answered 6/9, 2011 at 14:2 Comment(2)
I did such things with php and 1 time per month lock file somehow wasn't removed ...so I think it's not 100% percent solutionBurmeister
If you put the PID in the file, and check to see whether that's running (rather than just existence of the file), you might be able to more reliably remove the lock.Retuse
S
2

If you simply want to skip this rake task, you could also use the database to store information about the task progress (e.g. update a field when you start and finish a given task) and check that information before running each task.

However, if you want a queue-like behavior, you might want to consider creating a daemon to handle the tasks. The process is very simple and gives you a lot more control. There is a very good railscast about this: Custom Daemon

The daemon approach will also prevent rails environment from being loaded again on each task. This is especially useful if your rake tasks are frequent.

Schuh answered 13/9, 2011 at 2:33 Comment(0)
K
1

Here's my variant with file lock for rails rake tasks.

Put this in your rake task file (under namespace, so it wont overlap with other rake tasks):

def cron_lock(name)
  path = Rails.root.join('tmp', 'cron', "#{name}.lock")
  mkdir_p path.dirname unless path.dirname.directory?
  file = path.open('w')
  return if file.flock(File::LOCK_EX | File::LOCK_NB) == false
  yield
end

usage:

cron_lock 'namespace_task_name' do
  # your code
end

full example:

namespace :service do
  def cron_lock(name)
    path = Rails.root.join('tmp', 'cron', "#{name}.lock")
    mkdir_p path.dirname unless path.dirname.directory?
    file = path.open('w')
    return if file.flock(File::LOCK_EX | File::LOCK_NB) == false
    yield
  end

  desc 'description'
  task cleaning: :environment do
    cron_lock 'service_cleaning' do
      # your code
    end
  end
end
Kerstinkerwin answered 25/8, 2015 at 10:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.