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
5 Answers
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

- 1,619
- 1
- 19
- 30

- 2,556
- 1
- 16
- 24
-
2There's also flock (frequently in /usr/bin/flock) on some systems - the question didn't specify the OS. – James Moore Sep 18 '11 at 19:13
-
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. – yekta Nov 15 '13 at 15:45
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.

- 2,393
- 1
- 17
- 24
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.

- 9,794
- 9
- 54
- 85
-
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 solution – Fivell Sep 06 '11 at 14:09
-
2If 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. – spike Sep 06 '11 at 14:14
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.

- 11,701
- 4
- 35
- 40
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

- 2,175
- 5
- 21
- 23