sql - respaldo - script cron para actuar como una cola O una cola para cron?
script backup linux (3)
Apuesto a que alguien ya ha resuelto esto y que estoy usando los términos de búsqueda incorrectos para que Google me diga la respuesta, pero esta es mi situación.
Tengo un script que quiero ejecutar, pero quiero que se ejecute solo cuando esté programado y solo uno a la vez. (no se puede ejecutar el script simultáneamente)
Ahora la parte más difícil es decir que tengo una tabla llamada "myhappyschedule" que tiene los datos que necesito y la hora programada. Esta tabla puede tener múltiples horarios programados, incluso al mismo tiempo, cada uno ejecutaría este script. Entonces, esencialmente, necesito una cola cada vez que el script se activa y todos deben esperar cada uno antes de que termine. (a veces, esto puede tomar solo un minuto para que el script se ejecute, a veces, durante muchos minutos)
Lo que estoy pensando hacer es hacer un script que compruebe myhappyschedule cada 5 minutos y reúna los que están programados, los pone en una cola donde otro script puede ejecutar cada ''trabajo'' u ocurrencia en la cola en orden. Que todo esto suena desordenado.
Para hacer esto más largo, debería decir que les estoy permitiendo a los usuarios programar cosas en myhappyschedule y no editar crontab.
¿Qué se puede hacer con esto? ¿Bloqueos de archivos y scripts que invocan scripts?
Puede usar el comando at (1) dentro de su script para programar su próxima ejecución. Antes de que finalice, puede verificar myhappyschedule para el próximo tiempo de ejecución. No necesitas cron en absoluto, realmente.
agregue una columna exec_status
a myhappytable
(quizás también time_started
y time_finished
, vea pseudocódigo)
ejecuta el siguiente script cron cada x minutos
pseudocódigo de script cron:
[create/check pid lock (optional, but see "A potential pitfall" below)]
get number of rows from myhappytable where (exec_status == executing_now)
if it is > 0, exit
begin loop
get one row from myhappytable
where (exec_status == not_yet_run) and (scheduled_time <= now)
order by scheduled_time asc
if no such row, exit
set row exec_status to executing_now (maybe set time_started to now)
execute whatever command the row contains
set row exec_status to completed
(maybe also store the command output/return as well, set time_finished to now)
end loop
[delete pid lock file (complementary to the starting pid lock check)]
De esta forma, el script comprueba primero si ninguno de los comandos se está ejecutando, luego ejecuta el primer comando que aún no ejecuta, hasta que no haya más comandos para ejecutar en el momento dado. Además, puede ver qué comando se está ejecutando al consultar la base de datos.
Una posible trampa: si se cancela la secuencia de comandos cron, una tarea programada permanecerá en el estado de "ejecución_now". Para eso sirve el bloqueo pid al principio y al final: para ver si el script cron terminó correctamente. pseudocódigo de crear / verificar pidlock:
if exists pidlockfile then
check if process id given in file exists
if not exists then
update myhappytable set exec_status = error_cronscript_died_while_executing_this
where exec_status == executing_now
delete pidlockfile
else (previous instance still running)
exit
endif
endif
create pidlockfile containing cron script process id
Me encontré con esta pregunta mientras buscaba una solución al problema de las colas. Para beneficio de cualquier otra persona que busque aquí, está mi solución.
Combine esto con un cron que inicia trabajos tal como están programados (incluso si están programados para ejecutarse al mismo tiempo) y eso resuelve el problema que usted describió también.
Problema
- Como máximo, se debe ejecutar una instancia del script.
- Queremos seguir las solicitudes para procesarlas lo más rápido posible.
es decir. Necesitamos una tubería para el guión.
Solución:
Crea una canalización a cualquier script. Hecho usando un pequeño script bash (más abajo).
El script se puede llamar como
./pipeline "<any command and arguments go here>"
Ejemplo:
./pipeline sleep 10 &
./pipeline shabugabu &
./pipeline single_instance_script some arguments &
./pipeline single_instance_script some other_argumnts &
./pipeline "single_instance_script some yet_other_arguments > output.txt" &
..etc
La secuencia de comandos crea una nueva tubería con nombre para cada comando. Por lo tanto, lo anterior creará canalizaciones con nombre: sleep
, shabugabu
y single_instance_script
En este caso, la llamada inicial iniciará un lector y ejecutar single_instance_script
con some arguments
como argumentos. Una vez que se completa la llamada, el lector tomará la siguiente solicitud de la tubería y la ejecutará con some other_arguments
, completará, some other_arguments
el próximo etc ...
Este script bloqueará los procesos solicitantes, así que llámalo como un trabajo en segundo plano (y al final) o como un proceso separado con at
( at now <<< "./pipeline some_script"
)
#!/bin/bash -Eue
# Using command name as the pipeline name
pipeline=$(basename $(expr "$1" : ''/(^[^[:space:]]*/)'')).pipe
is_reader=false
function _pipeline_cleanup {
if $is_reader; then
rm -f $pipeline
fi
rm -f $pipeline.lock
exit
}
trap _pipeline_cleanup INT TERM EXIT
# Dispatch/initialization section, critical
lockfile $pipeline.lock
if [[ -p $pipeline ]]
then
echo "$*" > $pipeline
exit
fi
is_reader=true
mkfifo $pipeline
echo "$*" > $pipeline &
rm -f $pipeline.lock
# Reader section
while read command < $pipeline
do
echo "$(date) - Executing $command"
($command) &> /dev/null
done