2011-09-06 24 views
6

¿Es posible de alguna manera de ejecutar la tarea rake sólo si no se está ejecutando, quiero usar cron para ejecutar algunas tareas rastrillo rastrillo, pero la tarea no debe comenzar si llamada anterior no ha terminado Graciascomisión si ya se está ejecutando

Respuesta

12

Utilizo lockrun para evitar que las tareas cron se ejecuten varias veces (esto solo funciona al invocar el comando a través de la misma invocación lockrun, por lo que si necesita protegerse de varias rutas de invocación, deberá buscar otros métodos)

En su crontab, se invoca así:

*/5 * * * * /usr/local/bin/lockrun --lockfile=/tmp/this_task.lockrun -- cd /my/path && RAILS_ENV=production bundle exec rake this:task 
+1

gracias por la respuesta nunca escuchado sobre lockrun – Fivell

+2

También hay rebaños (con frecuencia en/usr/bin/flock) en algunos sistemas - la pregunta no especificaba el sistema operativo. –

+0

El problema con el rebaño es que no puede ejecutar un comando con más de un argumento, por lo que 'rake task_name' es dos argumentos y, por lo tanto, falla. – yekta

5

La solución general no específica de rake es utilizar un archivo pid como un bloqueo. Envolvería la tarea de rake en una secuencia de comandos que crea este archivo cuando ejecuta rake, lo elimina cuando Rake termina de ejecutarse, y lo busca antes de comenzar.

No estoy seguro si el rastrillo tiene algo incorporado, no sé de nada.

+0

Hice tales cosas con php y una vez al mes el archivo de bloqueo no se eliminó de alguna manera ... así que creo que no es una solución al 100% – Fivell

+1

Si coloca el PID en el archivo y comprueba si se está ejecutando (en lugar de solo la existencia del archivo), es posible que pueda eliminar el bloqueo de manera más confiable. – spike

+0

¡buena idea! gracias – Fivell

2

Si simplemente desea omitir esta tarea de rake, también puede usar la base de datos para almacenar información sobre el progreso de la tarea (por ejemplo, actualizar un campo al iniciar y finalizar una tarea determinada) y verificar esa información antes de ejecutar cada tarea.

Sin embargo, si desea un comportamiento similar a una cola, puede considerar crear un daemon para manejar las tareas. El proceso es muy simple y te da mucho más control. Hay una muy buena transmisión sobre esto: Custom Daemon

El enfoque daemon también evitará que los entornos de rieles se carguen nuevamente en cada tarea. Esto es especialmente útil si sus tareas de rake son frecuentes.

6

Además, se puede utilizar un fichero de bloqueo, pero manejarlo de la tarea:

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 

Esto probablemente podría ser extraído en algún tipo de módulo, pero entiendes la idea.

1

Aquí está mi variante con bloqueo de archivos para tareas de rastrillado de rieles.

poner esto en su archivo tarea rastrillo (bajo espacio de nombres, por lo que suele superponen con otras tareas rake):

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 

uso:

cron_lock 'namespace_task_name' do 
    # your code 
end 

ejemplo completo:

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 
Cuestiones relacionadas