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
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
rake task_name
is two arguments and therefore fails. –
Pogonia 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.
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.
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.
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
© 2022 - 2024 — McMap. All rights reserved.