BISO bietet ein Background-Job-System an, welches Hintergrund-Arbeiten definieren / ausführen kann. Dies können beliebige Aufgaben sein, welche entweder der Entkoppelung des Frontends dienen (Start über das UI, dann Job im Hintergrund ausführen), oder Maintenance-Arbeiten, welche als Job konfiguriert werden können.
Die Job-Ausführung kann auch wiederholt erfolgen: Jobs können sowohl einzelne / einmalig auszuführende Tasks wie auch in bestimmten Intervallen wiederholende Jobs sein. Beispielweise
können so täglich auszuführende Arbeiten definiert werden. Dies ist aber nicht zu verwechseln mit einem Scheduling wie cron: Jobs können nicht zu bestimmten Zeiten gestartet werden,
nur in bestimmen Intervallen wiederholt ausgeführt werden.
Ein Job definiert die Aufgabe, welche im Hintergrund ausgeführt wird. Der Job definiert den Wiederholungstyp (einzeln, wiederholend) und beinhaltet die für die Aufgabe notwendigen
Daten und Programmcode.
Ein MultiStepJob ist ein Job, welcher mehrere JobSteps instanziert und diese dann abarbeitet. Dies ist z.B. dann gewünscht, wenn der Job viele kleine Einzelschritte ausführen muss (Bsp: Abarbeiten einer Liste von Fällen).
Die **JobFactory**-Klasse dient zur Verwaltung der Jobs: Jobs werden nicht manuell erstellt / gestartet, sondern via die JobFactory-Klasse gemanagt.
In beiden Fällen müssen entsprechende Kind-Klassen definiert werden, welche die eigentliche Logik der abstrakten Methoden implementieren:
Um eigene Job-Klassen zu implementieren, können/müssen folgende Klassen implementiert werden:
Biso\App\jobs\Jobinit($options = null) und run()init($options = null) wird beim Erstellen des Jobs ausgeführt, nachdem der Job erstellt wurde.run() stellt die eigentliche Logik zum Ausführen des Jobs dar. Nach Abschluss muss der Status des Jobs zurückgegeben werden.Biso\App\jobs\MultiStepJobinit($options = null) und runStep(JobStep $step)init($options = null) wird beim Erstellen des Jobs ausgeführt, nachdem der Job erstellt wurde. Hier müssen die Zwischenschritte instanziert werden: Dazu werden neue Instanzen der Kind-Klasse Biso\App\jobs\JobStep erzeugt / gespeichert.runStep(JobStep $step) stellt die eigentliche Logik zum Ausführen eines Zwischenschritts dar. Nach Abschluss muss der Status des Zwischenschritts zurückgegeben werden.Die Job-Klassen sollen nicht manuell instanziert / gespeichert werden. Für das Job-Management dient die JobFactory-Klasse. Sie ist dafür zuständig, Jobs zu erstellen und zu starten:
<?php
use Biso\App\jobs\JobFactory;
$logger = Logger::getLogger('jobs');
$jobFactory = new JobFactory($logger);
// Erstellen eines neuen Jobs: Instanzieren einer spezifischen Job-Klasse:
// Dies erstellt den Job, und `init()` wird aufgerufen.
// Danach landet dieser in der Job-Queue.
$job = $jobFactory->createNewJob(MyJob::class, ['option1' => 'value1']);
// Starten des nächsten Jobs in der Queue:
// Blockiert solange, bis der Job fertig ist.
$job = $jobFactory->runNextNewJob();
// Laden eines bestehenden Jobs mit der richtigen Klasse:
$job = $jobFactory->loadJob($jobId);
<?php
use Biso\App\jobs\Job;
class SimpleJob extends Job {
/**
* Initialisierungsfunktion: Hier erhält der Job etwelche Parameter, die verarbeitet werden können:
*/
#[Override]
public function init($options = null) {
$this->getLogger()->info('SimpleJob is initializing. Status: ' . $this->status);
foreach ($options ?: [] as $key => $value) {
$this->getJobData()->{$key} = $value;
}
}
/**
* Funktion zum Ausführen des Jobs: Hier wird die eingentliche Arbeit verrichtet. Am Schluss
* muss der End-Status zurückgegeben werden:
*/
#[Override]
protected function run(): string {
$this->getLogger()->info('SimpleJob is running');
return static::STATUS_SUCCESS;
}
}
// Registration / Erstellen des Jobs:
$jobFactory = new JobFactory($logger);
$jobFactory->createNewJob(SimpleJob::class, ['option1' => 'value1']);
$jobFactory->runNextNewJob();
<?php
use Biso\App\jobs\JobStep;
use Biso\App\jobs\MultiStepJob;
class SimpleMultiStepJob extends MultiStepJob {
/**
* In der init()-Methode werden die einzelnen Zwischenschritte instanziert:
*/
#[Override]
public function init($options = null) {
for ($i = 0; $i < ($options['steps'] ?? 0); $i++) {
$step = new SimpleJobStep();
$step->job_id = $this->getId();
$step->getStepData()->number = $i;
$step->store();
}
}
/**
* runStep erhält den auszuführenden Zwischenschritt und implementiert die Logik.
* Der End-Status muss zurückgegeben werden:
*/
#[Override]
protected function runStep(JobStep $step): string {
$this->getLogger()->info("Step number: {$step->getStepData()->number}");
return static::STATUS_SUCCESS;
}
}
// Registration / Erstellen des Jobs:
$jobFactory = new JobFactory($logger);
$jobFactory->createNewJob(SimpleMultistepJob::class, ['steps' => 5]);
$jobFactory->runNextNewJob();
Jobs haben die Möglichkeit, am Schluss eine Benutzer-Info (Email) zu senden. Dabei wird die Email von der am Benutzer (user_id) zugewiesenen Person ermittelt.
Dazu dient auf dem Job die Methode Job::notifyUser($message). Diese kann zu einem beliebigen Zeitpunkt aufgerufen werden.
Eine Möglichkeit ist, dies im afterRun()-Hook zu machen:
<?php
use Biso\App\jobs\Job;
class DemoJob extends Job {
#[Override]
protected function afterRun() {
$this->notifyUser("Job abgeschlossen. 1234 Fälle wurden gelöscht");
}
}
Die notifyUser()-Methode sendet eine Email an den Benutzer, der den Job erstellt hat.
Für Jobs, welche am Schluss eine Mail-Notifikation versenden, muss ein SMTP-Sender in config.php definiert werden:
<?php
Config::set('smtp_sender', 'absender@domain.com');
Der Job-Runner wird mittels BISO-Commands ausgeführt:
# Starten eines Job-Runners:
./biso-cli job-runner run
# Starten des Cleanup-Prozesses:
# räumt alte / nicht aktualiserte Jobs auf.
./biso-cli job-runner cleanup
# Anzeigen Jobs:
./biso-cli job-runner list
# Anzeigen anstehender Jobs:
./biso-cli job-runner list new queued
# Anzeigen laufender Jobs:
./biso-cli job-runner list running
Wenn keine Jobs mehr abzuarbeiten sind, beendet sich der Job-Runner-Prozess. Der Job-Runner kann mittels cron-Job z.B. alle Minuten angestossen werden: Ist er (noch) am Laufen, beendet sich der Prozess wieder.
Für die parallele Abarbeitung von Jobs können mehrere Job-Runner-Prozesse gestartet werden. Dazu muss jedoch pro Prozess ein dediziertes Lockfile definiert werden:
./biso-cli job-runner run --lockfile /tmp/jobrunner-1.lock
./biso-cli job-runner run --lockfile /tmp/jobrunner-2.lock
./biso-cli job-runner run --lockfile /tmp/jobrunner-3.lock
Dies startet 3 Instanzen gleichzeitig. Jobs werden nur an einen Prozess verteilt.
Der Job-Runner muss regelmässig (z.B. alle 1 min) vom System-Scheduler (cron, Scheduled Tasks) angestossen werden:
Wir empfehlen daher folgende Scheduling-Konfiguration (hier am Beispiel Crontab):
# Min Hour DoM Month DoW
# Starten von 3 Instanzen, alle 1 Minuten:
* * * * * php /biso/webroot/biso-cli job-runner run --lockfile=/tmp/biso-runner-lock-1.lock
* * * * * php /biso/webroot/biso-cli job-runner run --lockfile=/tmp/biso-runner-lock-2.lock
* * * * * php /biso/webroot/biso-cli job-runner run --lockfile=/tmp/biso-runner-lock-3.lock
# Ausführen des Cleanups, um alte / gestorbene Jobs aufzuräumen (alle 6 Stunden):
* */6 * * * php /biso/webroot/biso-cli job-runner cleanup