Domanda

Scommetto che qualcuno ha già risolto questo problema e forse sto usando termini di ricerca errati per google per dirmi la risposta, ma ecco la mia situazione.

Ho uno script che voglio eseguire, ma voglio che venga eseguito solo quando pianificato e solo uno alla volta. (impossibile eseguire lo script contemporaneamente)

Ora la parte appiccicosa è che dire che ho una tabella chiamata " myhappyschedule " che ha i dati di cui ho bisogno e l'orario programmato. Questa tabella può avere più orari pianificati anche contemporaneamente, ognuno eseguirà questo script. Quindi, in sostanza, ho bisogno di una coda ogni volta che lo script viene attivato e tutti devono attendere che ciascuno prima che finisca. (a volte questo può richiedere solo un minuto per l'esecuzione dello script a volte i suoi molti molti minuti)

Quello che sto pensando di fare è creare uno script che controlla myhappyschedule ogni 5 minuti e raccoglie quelli programmati, inserendoli in una coda in cui un altro script può eseguire ogni 'lavoro' o occorrenza nella coda in ordine. Che tutto ciò suona disordinato.

Per allungare il tempo, dovrei dire che sto permettendo agli utenti di pianificare cose in myhappyschedule e non modificare crontab.

Cosa si può fare al riguardo? Blocchi di file e script che chiamano script?

È stato utile?

Soluzione

aggiungi una colonna exec_status a myhappytable (forse anche time_started e time_finished, vedi pseudocodice)

esegui il seguente cron script ogni x minuti

pseudocodice di cron script:

[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)]

In questo modo, lo script controlla innanzitutto se nessuno dei comandi è in esecuzione, quindi esegue il primo comando non ancora eseguito, fino a quando non ci sono più comandi da eseguire in un determinato momento. Inoltre, puoi vedere quale comando sta eseguendo interrogando il database.

Un potenziale trabocchetto: se lo script cron viene ucciso, un'attività pianificata rimarrà tra " execing_now " stato. Ecco a cosa serve il blocco pid all'inizio e alla fine: per vedere se lo script cron è terminato correttamente. pseudocodice di create / check 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

Altri suggerimenti

È possibile utilizzare il comando at (1) all'interno dello script per pianificare la sua prossima esecuzione. Prima di uscire, può controllare myhappyschedule per il prossimo periodo di esecuzione. In realtà non hai bisogno di cron.

Mi sono imbattuto in questa domanda mentre cercavo una soluzione al problema delle code. A beneficio di chiunque altro cerchi qui è la mia soluzione.

Combina questo con un cron che avvia i lavori come pianificato (anche se sono pianificati per essere eseguiti contemporaneamente) e che risolve anche il problema che hai descritto.

Problema


  • Almeno un'istanza dello script dovrebbe essere in esecuzione.
  • Vogliamo fornire richieste per elaborarle il più rapidamente possibile.

es. Abbiamo bisogno di una pipeline per lo script.

Soluzione:


Crea una pipeline per qualsiasi script. Fatto usando un piccolo script bash (più in basso).

Lo script può essere chiamato come
./pipeline "<any command and arguments go here>"

Esempio:

./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

Lo script crea un nuovo named pipe per ciascuno comando. Quindi quanto sopra creerà le pipe denominate: sleep, shabugabu e single_instance_script

In questo caso la chiamata iniziale avvierà un lettore ed eseguirà some arguments con some other_arguments come argomenti. Una volta completata la chiamata, il lettore prenderà la richiesta successiva dalla pipe ed eseguirà con at, completerà, afferrerà la successiva ecc ...

Questo script bloccherà i processi richiedenti, quindi chiamalo come processo in background (& amp; alla fine) o come processo distaccato con 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top