Cron-Skript als eine Warteschlange oder eine Warteschlange für cron zu handeln?

StackOverflow https://stackoverflow.com/questions/226473

  •  03-07-2019
  •  | 
  •  

Frage

Ich wette, dass jemand dies bereits gelöst hat und vielleicht bin ich mit den falschen Suchbegriffe für Google mir die Antwort zu sagen, aber hier ist meine Situation.

Ich habe ein Skript, das ich laufen soll, aber ich will es nur ausgeführt werden, wenn geplant und nur einen nach dem anderen. (Kann das Skript nicht gleichzeitig ausgeführt werden)

Nun ist der klebrige Teil ist, dass sagen, ich habe eine Tabelle „myhappyschedule“ genannt, die die Daten, die ich brauche und die geplante Zeit. Diese Tabelle kann mehrere geplanten Termine sogar zur gleichen Zeit hat, jeder würde dieses Skript ausführen. So im Wesentlichen brauche ich eine Warteschlange jedes Mal, wenn die Skript Feuer und sie müssen alle für jeden warten, bevor es zu beenden. (Manchmal kann dies nur eine Minute dauern, bis das Skript manchmal seine viele, viele Minuten auszuführen)

Was ich denke über das Tun ein Skript macht die myhappyschedule alle 5 Minuten überprüft und diejenigen einsammelt, die geplant sind, legt sie in eine Warteschlange, wo ein anderes Skript jeden ‚Job‘ ausführen kann, oder das Auftreten in der Warteschlange um. Was all dies klingt chaotisch.

Um dies zu mehr machen - ich würde sagen, dass ich damit die Benutzer der Dinge in myhappyschedule planen und nicht crontab bearbeiten.

Was kann dagegen unternommen werden? Dateisperren und Skripte Aufruf Skripte?

War es hilfreich?

Lösung

fügen Sie eine Spalte exec_status myhappytable (vielleicht auch time_started und time_finished finden Pseudo-Code)

Führen Sie den folgenden Cron-Skript alle x Minuten

Pseudo-Code von cron-Skript:

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

Auf diese Weise kann das Skript zunächst überprüft, ob keine der Befehle ausgeführt wird, dann läuft zunächst noch nicht Befehl ausführen, bis es nicht mehr Befehle sind im gegebenen Augenblick ausgeführt werden. Außerdem können Sie sehen, was Befehl ausführt Abfragen der Datenbank.

Ein potentielles pitfall: , wenn der Cron-Skript getötet wird, eine geplante Aufgabe wird in "executing_now" Zustand verbleibt. Das ist, was die pid Sperre am Anfang und Ende ist: um zu sehen, ob der Cron-Skript ordnungsgemäß beendet. Pseudo-Code von erstellen / 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

Andere Tipps

Sie können die unter (1) Befehl in Ihrem Skript verwenden, um seinen nächsten Lauf zu planen. Bevor es verlässt, kann es myhappyschedule für die nächste Laufzeit überprüfen. Sie brauchen nicht cron überhaupt, wirklich.

ich auf diese Frage kam, während eine Lösung für das Warteschlangen-Problem untersucht. Zum Wohl sonst jemand hier suchen ist meine Lösung.

In Kombination mit einem cron, die Arbeitsplätze beginnt, wie sie geplant sind (auch wenn sie geplant sind, die gleichzeitig ausgeführt werden) und das löst das Problem, das Sie als gut beschrieben.

Problem


  • Allenfalls eine Instanz des Skripts sollte ausgeführt werden.
  • Wir wollen Anfragen spulen, um sie so schnell wie möglich zu bearbeiten.

dh. Wir brauchen eine Pipeline an das Skript.

Lösung:


eine Pipeline zu jedem Skript erstellen. Geschah einen kleinen Bash-Skript (weiter unten).

Das Skript kann als
genannt werden ./pipeline "<any command and arguments go here>"

Beispiel:

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

Das Skript erstellt eine neue Named Pipe für jeden Befehl. So die oben wird Named Pipes create: sleep, shabugabu und single_instance_script

In diesem Fall wird der erste Aufruf wird ein Lesegerät und Lauf single_instance_script mit some arguments als Argumente starten. Sobald der Anruf beendet ist, wird der Leser die nächste Anforderung aus dem Rohr greifen und führt mit some other_arguments, komplett, greift die nächste etc ...

Dieses Skript blockiert Prozesse anfordert, so dass es als Hintergrundjob nennen (& am Ende) oder als freistehenden Prozess mit 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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top