He programado que se ejecute un trabajo cron cada minuto, pero a veces el script tarda más de un minuto en finalizar y no quiero que los trabajos comiencen a "apilarse" unos sobre otros. Supongo que este es un problema de concurrencia, es decir, la ejecución del script debe ser mutuamente excluyente.
Para resolver el problema, hice que el script buscara la existencia de un archivo en particular (" lockfile.txt ") y salga si existe o touch
si no. ¡Pero este es un semáforo bastante pésimo! ¿Hay alguna práctica recomendada que deba conocer? ¿Debería haber escrito un demonio en su lugar?
fuente
flock -n file command
yflock -n file -c command
?-c
ejecuta el comando especificado a través de un shell (según la página de manual), mientras que la forma "desnuda" (no-c
) soloexec
es el comando dado . Poner algo a través del shell le permite hacer cosas similares al shell (como ejecutar múltiples comandos separados con;
o&&
), pero también lo abre a los ataques de expansión del shell si está utilizando una entrada no confiable.frequent_cron_job
comando (hipotético) que intentó mostrar que se ejecutaba cada minuto. Lo eliminé porque no agregó nada útil y causó confusión (la suya, si nadie más ha pasado los años).La mejor manera en shell es usar flock (1)
fuente
99
y>
así es99> /...
En realidad,
flock -n
se puede usar en lugar delckdo
*, por lo que usará código de desarrolladores de kernel.Sobre la base del ejemplo de womble , escribirías algo como:
Por cierto, mirando el código, todos
flock
,lockrun
ylckdo
hacer exactamente lo mismo, por lo que es sólo una cuestión de lo que es más fácilmente disponible para usted.fuente
Puedes usar un archivo de bloqueo. Cree este archivo cuando comience el script y elimínelo cuando finalice. El script, antes de ejecutar su rutina principal, debe verificar si el archivo de bloqueo existe y proceder en consecuencia.
Lockfiles son utilizados por initscripts y por muchas otras aplicaciones y utilidades en sistemas Unix.
fuente
No ha especificado si desea que el script espere a que se complete la ejecución anterior o no. Al decir "No quiero que los trabajos comiencen a" apilarse "unos sobre otros", supongo que estás insinuando que quieres que el script salga si ya se está ejecutando,
Entonces, si no quieres depender de lckdo o similar, puedes hacer esto:
fuente
Esto también podría ser una señal de que estás haciendo algo incorrecto. Si sus trabajos se ejecutan tan de cerca y con tanta frecuencia, tal vez debería considerar eliminar el cronograma y convertirlo en un programa estilo demonio.
fuente
Su demonio cron no debería invocar trabajos si aún se están ejecutando instancias anteriores de ellos. Soy el desarrollador de un cron daemon dcron , y tratamos específicamente de evitarlo. No sé cómo Vixie cron u otros demonios manejan esto.
fuente
Recomendaría usar el comando run-one , mucho más simple que lidiar con los bloqueos. De los documentos:
run-one es un script de contenedor que no ejecuta más de una instancia única de algún comando con un conjunto único de argumentos. Esto suele ser útil con cronjobs, cuando no desea que se ejecute más de una copia a la vez.
run-this-one es exactamente como run-one, excepto que usará pgrep y kill para encontrar y eliminar cualquier proceso en ejecución propiedad del usuario y que coincida con los comandos y argumentos de destino. Tenga en cuenta que run-this-one se bloqueará al intentar eliminar procesos coincidentes, hasta que todos los procesos coincidentes estén muertos.
run-one-constantemente opera exactamente como run-one, excepto que reaparece "COMANDO [ARGS]" cada vez que sale de COMANDO (cero o no cero).
keep-one-running es un alias para run-one-constantemente.
ejecutar-uno-hasta-el-éxito funciona exactamente como ejecutar-uno-constantemente, excepto que reaparece "COMANDO [ARGS]" hasta que COMANDO sale con éxito (es decir, sale de cero).
ejecutar-uno-hasta-falla funciona exactamente como ejecutar-uno-constantemente, excepto que reaparece "COMANDO [ARGS]" hasta que COMANDO sale con falla (es decir, sale de cero).
fuente
Ahora que systemd está fuera, hay otro mecanismo de programación en los sistemas Linux:
UNA
systemd.timer
En
/etc/systemd/system/myjob.service
o~/.config/systemd/user/myjob.service
:En
/etc/systemd/system/myjob.timer
o~/.config/systemd/user/myjob.timer
:Si la unidad de servicio ya se está activando la próxima vez que se active el temporizador, entonces no se iniciará otra instancia del servicio .
Una alternativa, que inicia el trabajo una vez al inicio y un minuto después de que finalice cada ejecución:
fuente
He creado un jar para resolver este problema, ya que se están ejecutando cron duplicados que podrían ser java o shell cron. Simplemente pase el nombre cron en Duplicates.CloseSessions ("Demo.jar"), esto buscará y matará a pid existente para este cron excepto el actual. He implementado un método para hacer esto. Cadena proname = ManagementFactory.getRuntimeMXBean (). GetName (); Cadena pid = proname.split ("@") [0]; System.out.println ("PID actual:" + pid);
Y luego mata la cadena killid con nuevamente el comando de shell
fuente
La respuesta de @Philip Reynolds comenzará a ejecutar el código después del tiempo de espera de 5 segundos de todos modos sin obtener el bloqueo. Seguir a Flock no parece estar funcionando . Modifiqué la respuesta de @Philip Reynolds a
para que el código nunca se ejecute simultáneamente. En cambio, después de 5 segundos de espera, el proceso saldrá con 1 si no obtuvo el bloqueo para entonces.
fuente