Heim  >  Artikel  >  Backend-Entwicklung  >  Verwenden von Supervisor zur Abwicklung der Ausführung eines Symfony-Befehls

Verwenden von Supervisor zur Abwicklung der Ausführung eines Symfony-Befehls

WBOY
WBOYOriginal
2024-09-07 06:34:02813Durchsuche

Einführung

In diesem Beitrag erfahren Sie, wie Sie supervisord verwenden, um die Ausführung eines Symfony-Befehls zu verwalten. Grundsätzlich erlaubt uns der Vorgesetzte:

  • Befehl automatisch starten
  • Befehl automatisch neu starten
  • Geben Sie die Anzahl der Prozesse an, die der Supervisor starten soll.

Das Problem

Manchmal greifen wir auf die Unix-Crontab zurück, um die Ausführung von Prozessen zu automatisieren. Dies mag in den meisten Fällen funktionieren, aber es kann Situationen geben, in denen es Probleme verursachen kann.

Stellen wir uns vor, wir hätten eine Datenbanktabelle, die die Benachrichtigungen der Benutzer protokolliert. Die Tabelle speichert die folgenden Informationen:

  • Benutzer
  • Text
  • Kanal
  • Status (WARTET, GESENDET)
  • erstellt am
  • aktualisiert um

Andererseits haben wir einen Befehl codiert, dessen Ausführung den nächsten Schritten folgt:

  • Frägt die letzten WAITING-Benachrichtigungen ab
  • Läuft die abgefragten Benachrichtigungen in einer Schleife ab und:
    • Sendet jedes einzelne an den entsprechenden Benutzer.
    • Aktualisiert den Benachrichtigungsstatus von WAITING auf GESENDET

Wir haben diesen Befehl in der Linux-Crontab so eingestellt, dass er von Zeit zu Zeit ausgeführt wird (1 Minute, 2 Minuten usw.). So weit so gut.

Stellen wir uns nun vor, dass der aktuelle Prozess 500 Benachrichtigungen abgefragt hat und wenn er 400 gesendet hat, startet ein neuer Prozess. Das bedeutet, dass der neue Prozess die 100 Benachrichtigungen abfragt, die vom letzten Prozess noch nicht aktualisiert wurden, plus die neuen:

Using Supervisor to handle a Symfony Command execution

Dies kann dazu führen, dass diese 100 Benachrichtigungen zweimal gesendet werden, da beide Prozesse sie abgefragt haben.

Die Lösung

Als Lösung können wir auf den Einsatz eines Supervisors zurückgreifen. Es hält unseren Prozess am Laufen und startet ihn bei Bedarf neu. Auf diese Weise behalten wir nur einen Prozess bei und vermeiden Überschneidungen. Lassen Sie uns analysieren, wie der Befehl aussehen sollte:

#[AsCommand(
    name: 'app:notification'
)]
class NotificationCommand extends Command
{
    private bool $forceFinish = false;

    protected function configure(): void
    {
        $this
            ->addOption('time-limit', null, InputOption::VALUE_OPTIONAL, 'Max time alive in seconds')
            ->addOption('time-between-calls', null, InputOption::VALUE_OPTIONAL, 'Time between every loop call')

        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $this->forceFinish = false;
        pcntl_signal(SIGTERM, [$this, 'signalHandler']);
        pcntl_signal(SIGINT, [$this, 'signalHandler']);

        $timeLimit = $input->getOption('time-limit');
        $timeBetweenCalls = $input->getOption('time-between-calls');
        $dtMax = (new \DateTimeImmutable())->add(\DateInterval::createFromDateString("+ {$timeLimit} seconds"));

        do{
           // Here we should execute a service to query and send notifications
           // ......

           sleep($timeBetweenCalls);
           $dtCurrent = new \DateTimeImmutable();

        }while($dtCurrent < $dtMax && !$this->forceFinish);

        return Command::SUCCESS;
    }

    public function signalHandler(int $signalNumber): void
    {
        echo 'Signal catch: ' . $signalNumber . PHP_EOL;
        match ($signalNumber) {
            SIGTERM, SIGINT => $this->forceFinish = true,
            default => null
        };
    }
}

Lassen Sie uns den Befehl Schritt für Schritt erklären:

  • Die Methode configure deklariert Eingabeoptionen:

    • Zeitlimit: Maximale Zeit, die der Befehlsprozess aktiv sein kann. Danach wird es beendet und der Supervisor startet es neu.
    • time-between-calls: Zeit zum Schlafen nach jeder Schleifeniteration. Die Schleife ruft den Dienst auf, der Benachrichtigungen verarbeitet und während dieser Zeit in den Ruhezustand wechselt.
  • Die Methode execute verhält sich wie folgt:

    • Setzt die Klassenvariable forceFinish auf true
    • Verwendet die PHP-pnctl-Bibliothek, um die Methode signalHandler für die Verarbeitung der Unix-Signale SIGTERM und SIGINT zu registrieren.
    • Ruft die Eingabeoptionswerte ab und berechnet das maximale Datum, an dem der Befehl aktiv sein kann, bis der Optionswert Zeitlimit verwendet wird.
    • Die do-while-Schleife führt den erforderlichen Code aus, um die Benachrichtigungen abzurufen und zu senden (sie wird nicht in den Befehl eingefügt, stattdessen gibt es Kommentare). Anschließend wird die durch die Option Zeit zwischen Anrufen festgelegte Zeit in den Ruhezustand versetzt, bevor fortgefahren wird.
    • Wenn das aktuelle Datum (das in jeder Schleifeniteration berechnet wird) niedriger als das maximale Datum ist und forceFinish falsch ist, wird die Schleife fortgesetzt. Andernfalls wird der Befehl beendet.
  • Die Funktion signalHandler fängt die Unix-Signale SIGTERM und SIGINT ab. SIGINT ist das Signal, das gesendet wird, wenn wir Strg+C drücken, und SIGTERM ist das Standardsignal, wenn wir den Kill-Befehl verwenden. Wenn die Funktion signalHandler sie erkennt, setzt sie die Variable forceFinish auf „true“, sodass der Befehl nach Abschluss der aktuellen Schleife beendet wird, da die Variable forceFinish vorhanden ist nicht mehr falsch. Dadurch können Benutzer den Vorgang beenden, ohne warten zu müssen, bis das maximale Datum abgelaufen ist.

Supervisor konfigurieren

Bisher haben wir den Befehl erstellt. Jetzt ist es an der Zeit, den Supervisor so einzurichten, dass er damit umgehen kann. Bevor wir mit der Konfiguration beginnen, müssen wir Supervisor installieren. Sie können dies tun, indem Sie den folgenden Befehl ausführen:

sudo apt update && sudo apt install supervisor

Nach der Installation können Sie sicherstellen, dass Supervisor ausgeführt wird, indem Sie den nächsten Befehl ausführen:

sudo systemctl status supervisor

Supervisor-Konfigurationsdateien werden im folgenden Ordner abgelegt: /etc/supervisor/conf.d. Erstellen wir eine Datei mit dem Namen notif.conf und fügen den folgenden Inhalt ein:

command=php <your_project_folder>/bin/console app:notifications --time-limit=120 --time-between-calls=10
user=<your_user>
numprocs=1
autostart=true
autorestart=true
process_name=%(program_name)s_%(process_num)02d

Lassen Sie uns jeden Schlüssel erklären:

  • Befehl: Der Befehl zum Starten
  • Benutzer: Der Unix-Benutzer, der den Befehl ausführt
  • numprocs: Die Anzahl der auszuführenden Prozesse
  • Autostart: Ob der Befehl automatisch gestartet werden soll
  • Autostart: Ob der Befehl automatisch neu gestartet werden soll
  • Prozessname: Das Befehls-Unix-Prozessnamenformat.

Mit dieser Konfiguration wird der Befehl app:notifications maximal 120 Sekunden lang ausgeführt und nach jeder Schleife 10 Sekunden lang in den Ruhezustand versetzt. Nach Ablauf von 120 Sekunden oder Zwischenspeichern eines Unix-Signals verlässt der Befehl die Schleife und wird beendet. Dann wird der Vorgesetzte es erneut starten.

Abschluss

Wir haben gelernt, wie man Supervisor verwendet, um einen Befehl am Laufen zu halten, ohne die Crontab verwenden zu müssen. Dies kann nützlich sein, wenn sich die von der Crontab gestarteten Prozesse überschneiden und zu Datenbeschädigungen führen können.

Im letzten Buch, das ich geschrieben habe, zeige ich, wie man Supervisor verwendet, um die Symfony Messenger-Worker am Laufen zu halten. Wenn Sie mehr wissen möchten, finden Sie das Buch hier: Building an Operation-Oriented Api using PHP and the Symfony Framework: A Step-by-Step Guide

Das obige ist der detaillierte Inhalt vonVerwenden von Supervisor zur Abwicklung der Ausführung eines Symfony-Befehls. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn