wake-up-neo.net

Führen Sie das PHP-Skript als Daemon-Prozess aus

Ich muss ein PHP-Skript als Daemon-Prozess ausführen (auf Anweisungen warten und Sachen erledigen). cron job erledigt das nicht für mich, da bei eintreffen des unterrichts Maßnahmen ergriffen werden müssen. Ich weiß, dass PHP aufgrund von Speicherverwaltungsproblemen nicht wirklich die beste Option für Daemon-Prozesse ist, aber aus verschiedenen Gründen muss ich in diesem Fall PHP verwenden. Ich bin auf ein Tool von libslack namens Daemon ( http://libslack.org/daemon ) gestoßen, das mir scheinbar beim Verwalten von Daemon-Prozessen hilft, aber in den letzten 5 Jahren gab es keine Updates Wenn Sie andere Alternativen kennen, die für meinen Fall geeignet sind. Jede Information wird wirklich geschätzt.

138
Beier

Sie können Ihr PHP-Skript über die Befehlszeile (d. H. Bash) starten, indem Sie verwenden 

Nohup php myscript.php & 

der & stellt Ihren Prozess in den Hintergrund.

Bearbeiten:
Ja, es gibt einige Nachteile, die jedoch nicht kontrolliert werden können. Das ist einfach falsch.
Ein einfacher kill processid stoppt es. Und es ist immer noch die beste und einfachste Lösung. 

156

Eine andere Option ist die Verwendung von Upstart . Es wurde ursprünglich für Ubuntu entwickelt (und ist standardmäßig im Lieferumfang enthalten), soll aber für alle Linux-Distributionen geeignet sein.

Dieser Ansatz ist ähnlich zu Supervisord und daemontools , als er den Dämon beim Systemstart automatisch startet und bei Abschluss des Skripts automatisch startet.

So richten Sie es ein:

Erstellen Sie eine neue Skriptdatei unter /etc/init/myphpworker.conf. Hier ist ein Beispiel:

# Info
description "My PHP Worker"
author      "Jonathan"

# Events
start on startup
stop on shutdown

# Automatically respawn
respawn
respawn limit 20 5

# Run the script!
# Note, in this example, if your PHP script returns
# the string "ERROR", the daemon will stop itself.
script
    [ $(exec /usr/bin/php -f /path/to/your/script.php) = 'ERROR' ] && ( stop; exit 1; )
end script

Starten und Stoppen Ihres Daemons:

Sudo service myphpworker start
Sudo service myphpworker stop

Prüfen Sie, ob Ihr Daemon läuft:

Sudo service myphpworker status

Vielen Dank

Ein großer Dank geht an Kevin van Zonneveld , wo ich diese Technik gelernt habe.

150
Jonathan

Wenn Sie - eine Kopie von Advanced Programming in der UNIX-Umgebung erwerben können. Das gesamte Kapitel 13 ist der Daemon-Programmierung gewidmet. Beispiele sind in C, aber alle Funktionen, die Sie benötigen, haben Wrapper in PHP (im Wesentlichen die Erweiterungen pcntl und posix ).

In wenigen Worten - das Schreiben eines Daemons (dies ist nur auf * nix-basierten Betriebssystemen möglich - Windows verwendet Dienste) sieht folgendermaßen aus:

  1. Rufen Sie umask(0) auf, um Berechtigungsprobleme zu vermeiden.
  2. fork() und den übergeordneten Exit haben.
  3. Rufen Sie setsid() auf.
  4. Setup-Signalverarbeitung von SIGHUP (normalerweise wird dies ignoriert oder verwendet, um dem Daemon zu signalisieren, seine Konfiguration neu zu laden) und SIGTERM (um dem Prozess zu sagen, dass er ordnungsgemäß beendet werden soll).
  5. fork() noch einmal und der übergeordnete Exit.
  6. Ändern Sie das aktuelle Arbeitsverzeichnis mit chdir() .
  7. fclose()stdin, stdout und stderr und schreiben Sie ihnen nicht. Der richtige Weg ist, diese entweder auf /dev/null oder auf eine Datei umzuleiten, aber ich konnte keinen Weg finden, dies in PHP zu tun. Wenn Sie den Dämon starten, können Sie sie mithilfe der Shell umleiten (Sie müssen selbst herausfinden, wie das geht, ich weiß es nicht :).
  8. Machen Sie Ihre Arbeit!

Da Sie PHP verwenden, sollten Sie auch auf zyklische Verweise achten, da der PHP - Garbage Collector vor PHP 5.3 keine Möglichkeit hat, diese Verweise zu sammeln, und der Prozess wird Speicherlecks verursachen, bis er schließlich verloren geht stürzt ab.

47
Emil Ivanov

Mit dem neuen systemd können Sie einen Dienst (auf Rhel-basierter Linux-Basis) erstellen.

Sie müssen eine Datei oder ein symlink in /etc/systemd/system/ erstellen, z. myphpdaemon.service und platzieren Sie einen Inhalt wie diesen, myphpdaemon ist der Name des Dienstes:

[Unit]
Description=My PHP Daemon Service
#May your script needs mysql or other services to run, eg. mysql memcached
Requires=mysqld.service memcached.service 
After=mysqld.service memcached.service

[Service]
User=root
Type=simple
TimeoutSec=0
PIDFile=/var/run/myphpdaemon.pid
ExecStart=/usr/bin/php -f /srv/www/myphpdaemon.php arg1 arg2> /dev/null 2>/dev/null
#ExecStop=/bin/kill -HUP $MAINPID #It's the default you can change whats happens on stop command
#ExecReload=/bin/kill -HUP $MAINPID
KillMode=process

Restart=on-failure
RestartSec=42s

StandardOutput=null #If you don't want to make toms of logs you can set it null if you sent a file or some other options it will send all php output to this one.
StandardError=/var/log/myphpdaemon.log
[Install]
WantedBy=default.target

Sie können die Dienste mit dem Befehl starten, abrufen, abrufen und neu starten 

systemctl <start|status|restart|stop|enable> myphpdaemon 

Das PHP -Skript sollte eine Art "Schleife" haben, um weiter ausgeführt zu werden.

<?php
gc_enable();//
while (!connection_aborted() || PHP_SAPI == "cli") {

  //Code Logic

  //sleep and usleep could be useful
    if (PHP_SAPI == "cli") {
        if (Rand(5, 100) % 5 == 0) {
            gc_collect_cycles(); //Forces collection of any existing garbage cycles
        }
    }
}

Arbeitsbeispiel:

[Unit]
Description=PHP APP Sync Service
Requires=mysqld.service memcached.service
After=mysqld.service memcached.service

[Service]
User=root
Type=simple
TimeoutSec=0
PIDFile=/var/run/php_app_sync.pid
ExecStart=/bin/sh -c '/usr/bin/php -f /var/www/app/private/server/cron/app_sync.php  2>&1 > /var/log/app_sync.log'
KillMode=mixed

Restart=on-failure
RestartSec=42s

[Install]
WantedBy=default.target

Wenn Ihr PHP einmal in einem Zyklus ausgeführt werden soll (wie ein Diggest), sollten Sie ein Shell- oder Bash-Skript verwenden, um direkt in der systemd-Servicedatei anstelle von PHP aufgerufen zu werden. Beispiel:

#!/usr/bin/env bash
script_path="/app/services/"

while [ : ]
do
#    clear
    php -f "$script_path"${1}".php" fixedparameter ${2}  > /dev/null 2>/dev/null
    sleep 1
done

Wenn Sie diese Option wählen, sollten Sie die Option KillMode in mixed in prozesse ändern, bash (main) und php (child) werden beendet.

ExecStart=/app/phpservice/runner.sh phpfile parameter  > /dev/null 2>/dev/null
KillMode=process

Hinweis: Jedes Mal, wenn Sie Ihren "myphpdaemon.service" ändern, müssen Sie Führen Sie `systemctl daemon-reload 'aus, aber machen Sie sich Sorgen, wenn Sie dies nicht tun, wird es .__ sein. gefragt, wann es erforderlich ist.

40
LeonanCarvalho

Ich habe eine große Anzahl von PHP - Daemons. 

Ich stimme mit Ihnen überein, dass PHP nicht die beste (oder sogar eine gute) Sprache dafür ist, aber die Daemons teilen sich den Code mit den weborientierten Komponenten, so dass es insgesamt eine gute Lösung für uns ist.

Wir verwenden dafür Daemontools. Es ist intelligent, sauber und zuverlässig. Tatsächlich verwenden wir es, um alle unsere Daemons auszuführen.

Sie können dies unter http://cr.yp.to/daemontools.html überprüfen.

BEARBEITEN: Eine kurze Liste der Funktionen.

  • Startet den Daemon automatisch beim Neustart
  • Starten Sie automatisch dameon neu, wenn ein Fehler auftritt
  • Die Protokollierung wird für Sie übernommen, einschließlich Rollover und Bereinigung
  • Verwaltungsschnittstelle: 'svc' und 'svstat'
  • UNIX-freundlich (vielleicht kein Plus für alle)
24
Phil Wallach

Sie können

  1. Verwenden Sie Nohup wie von Henrik vorgeschlagen.
  2. Verwenden Sie screen und führen Sie Ihr PHP - Programm als regulären Prozess aus. Dadurch haben Sie mehr Kontrolle als mit Nohup
  3. Verwenden Sie einen Daemoniser wie http://supervisord.org/ (er ist in Python geschrieben, kann jedoch jedes Befehlszeilenprogramm dämonisieren und Ihnen eine Fernbedienung geben, um es zu verwalten). 
  4. Schreiben Sie Ihren eigenen Daemonise-Wrapper, wie es von Emil vorgeschlagen wurde, aber es ist übertrieben IMO.

Ich würde die einfachste Methode empfehlen (Bildschirm meiner Meinung nach) und dann, wenn Sie mehr Funktionen oder Funktionen wünschen, zu komplexeren Methoden übergehen. 

14
Noufal Ibrahim

Es gibt mehr als einen Weg, um dieses Problem zu lösen.

Ich kenne die Besonderheiten nicht, aber vielleicht gibt es eine andere Möglichkeit, den PHP - Prozess auszulösen. Wenn Sie beispielsweise den Code basierend auf Ereignissen in einer SQL-Datenbank ausführen möchten, können Sie einen Auslöser einrichten, um Ihr Skript auszuführen. Dies ist unter PostgreSQL sehr einfach durchzuführen: http://www.postgresql.org/docs/current/static/external-pl.html .

Ehrlich gesagt glaube ich, dass Sie am besten einen Damon-Prozess mit Nohup erstellen. Nohup ermöglicht die Ausführung des Befehls auch nach Abmeldung des Benutzers:

Nohup php myscript.php &

Es gibt jedoch ein sehr ernstes Problem. Wie Sie sagten, der Speichermanager von PHP ist ein kompletter Müll, wurde mit der Annahme erstellt, dass ein Skript nur für einige Sekunden ausgeführt wird und dann existiert. Ihr PHP Skript verwendet bereits nach wenigen Tagen GIGABYTES des Speichers. Sie MÜSSEN AUCH ein Cron-Skript erstellen, das alle 12 oder vielleicht 24 Stunden ausgeführt wird und das PHP-Skript wie folgt abtötet und erneut erzeugt:

killall -3 php
Nohup php myscript.php &

Aber was wäre, wenn sich das Drehbuch mitten im Job befand? Nun, kill-3 ist ein Interrupt, es ist das Gleiche wie ein Strg + C auf der CLI. Ihr PHP-Skript kann diesen Interrupt mit Hilfe der pcntl-Bibliothek PHP fangen und beenden: http://php.oregonstate.edu/manual/de/function.pcntl-signal.php

Hier ist ein Beispiel:

function clean_up() {
  GLOBAL $lock;
  mysql_close();
  fclose($lock)
  exit();
}
pcntl_signal(SIGINT, 'clean_up');

Die Idee hinter dem $ lock ist, dass das Skript PHP eine Datei mit einem fopen ("file", "w"); öffnen kann. Es kann nur ein Prozess über eine Schreibsperre für eine Datei verfügen, sodass Sie sicherstellen können, dass nur eine Kopie Ihres PHP - Skripts ausgeführt wird. 

Viel Glück!

11
rook

Kevin van Zonneveld schrieb einen sehr schönen ausführlichen Artikel dazu , in seinem Beispiel verwendet er das System_Daemon PEAR Paket (letztes Veröffentlichungsdatum am 2009-09-02).

10
Alix Axel

Check out https://github.com/shaneharter/PHP-Daemon

Dies ist eine objektorientierte Daemon-Bibliothek. Es hat eine integrierte Unterstützung für Dinge wie Protokollierung und Fehlerbehebung, und es gibt Unterstützung für die Erstellung von Hintergrundarbeitern. 

6
Shane H

Ich habe kürzlich eine plattformübergreifende Lösung (Windows, Mac und Linux) für das Problem der Ausführung von PHP -Skripts als Daemons benötigt. Ich habe das Problem gelöst, indem ich meine eigene C++ - basierte Lösung geschrieben und Binärdateien erstellt habe:

https://github.com/cubiclesoft/service-manager/

Volle Unterstützung für Linux (über sysvinit), aber auch Windows NT-Dienste und Mac OSX-Start.

Wenn Sie nur Linux benötigen, funktionieren einige der hier vorgestellten Lösungen gut und je nach Geschmack. Es gibt heutzutage auch Upstart und systemd, die Rückschläge auf sysvinit-Skripte haben. Die Hälfte des Einsatzes von PHP ist jedoch, dass es plattformübergreifend ist. In der Sprache geschriebener Code hat also eine gute Chance, überall so zu arbeiten, wie er ist. Mängel treten auf, wenn bestimmte Aspekte der systemeigenen externen Betriebssystemebene auftreten, z. B. Systemdienste. Dieses Problem tritt jedoch bei den meisten Skriptsprachen auf.

Es ist keine gute Idee, Signale zu fangen, als jemand, der hier in PHP userland vorgeschlagen wurde. Lesen Sie die Dokumentation zu pcntl_signal() sorgfältig durch, und Sie werden schnell erfahren, dass PHP Signale mit einigen unangenehmen Methoden (insbesondere "Ticks") verarbeitet, die eine Reihe von Zyklen für etwas kauen, das von Prozessen (d. H. Signale) selten gesehen wird. Das Signalhandling in PHP ist auf POSIX-Plattformen auch kaum verfügbar und die Unterstützung hängt von der PHP-Version ab. Es klingt anfangs nach einer anständigen Lösung, ist aber nicht wirklich nützlich.

PHP hat sich im Laufe der Zeit auch mit Speicherleckproblemen verbessert. Sie müssen immer noch vorsichtig sein (der DOM-XML-Parser neigt immer noch dazu, durchzusickern), aber ich sehe heutzutage selten durchgehende Prozesse und der PHP Bug-Tracker ist im Vergleich zu den Tagen von früher ziemlich leise.

3
CubicleSoft

Wie bereits erwähnt, ist die Ausführung von PHP als Daemon recht einfach und kann mit einer einzigen Befehlszeile ausgeführt werden. Aber das eigentliche Problem ist, dass es weiter läuft und verwaltet wird. Ich hatte das gleiche Problem schon vor einiger Zeit, und obwohl es bereits eine Vielzahl von Lösungen gibt, haben die meisten von ihnen viele Abhängigkeiten oder sind schwierig zu verwenden und für grundlegende Anwendungen nicht geeignet. Ich habe ein Shell-Skript geschrieben, das einen beliebigen Prozess/jede Anwendung, einschließlich PHP cli-Skripts, verwalten kann. Es kann als Cronjob zum Starten der Anwendung festgelegt werden und enthält die Anwendung und die Verwaltung. Wenn sie erneut ausgeführt wird, z. B. über denselben Cronjob, wird überprüft, ob die App ausgeführt wird oder nicht. Wenn dies der Fall ist, wird sie einfach beendet und die vorherige Instanz der Anwendung wird weiterhin verwaltet.

Ich habe es zu github hochgeladen. Sie können es gerne verwenden: https://github.com/sinasalek/EasyDeamonizer

EasyDeamonizer

Wacht einfach über Ihre Anwendung (Starten, Neustarten, Protokollieren, Überwachen usw.). ein generisches Skript, um sicherzustellen, dass Ihre Anwendung ordnungsgemäß ausgeführt wird. Es verwendet absichtlich den Prozessnamen instread von pid/lock-Datei, um alle Nebeneffekte zu vermeiden und das Skript so einfach und umständlich wie möglich zu halten, sodass es auch beim Neustart von EasyDaemonizer selbst funktioniert

  • Startet die Anwendung und optional eine benutzerdefinierte Verzögerung für jeden Start
  • Stellt sicher, dass nur eine Instanz ausgeführt wird
  • Überwacht die CPU-Nutzung und startet die App automatisch neu, wenn sie den definierten Schwellenwert erreicht
  • Festlegen, dass EasyDeamonizer über cron ausgeführt wird, um es erneut auszuführen, wenn es aus irgendeinem Grund angehalten wurde
  • Protokolliert seine Aktivität
1
Sina Salek

Erweitern von Emil Ivaov answer, Sie können folgende Schritte ausführen, um STDIN, STDOUT UND STDERROR in PHP zu schließen

if (!fclose(STDIN)) {
    exit("Could not close STDIN");
}

if (!fclose(STDOUT)) {
    exit("Could not close STDOUT");
}

if (!fclose(STDERR)) {
    exit("Could not close STDERR");
}

$STDIN = fopen('/dev/null', 'r');
$STDOUT = fopen('/dev/null', 'w');
$STDERR = fopen('/var/log/our_error.log', 'wb');

Grundsätzlich schließen Sie die Standard-Streams, sodass PHP keinen Platz zum Schreiben hat. Die folgenden fopen-Aufrufe setzen den Standard IO auf /dev/null.

Ich habe dies aus dem Buch von Rob Aley - PHP außerhalb des Web gelesen

1
Raheel Khan

Ich habe einen einfachen PHP-Daemon geschrieben und eingesetzt, der Code ist hier online

https://github.com/jmullee/PhpUnixDaemon

Features: Privileg-Drop, Signalverarbeitung, Protokollierung

Ich habe es in einem Queue-Handler verwendet (Anwendungsfall: löse eine lange Operation von einer Webseite aus aus, ohne dass das Seiten erzeugende PHP wartet, dh eine asynchrone Operation startet) https://github.com/jmullee/PhpIPCMessageQueue

0
jmullee

sie können PM2 hier überprüfen, ist http://pm2.keymetrics.io/

erstellen Sie eine ssh-Datei, z. B. worker.sh, die Sie in Ihr PHP-Skript einfügen.

worker.sh

php /path/myscript.php

daemon start

pm2 start worker.sh

Prost, das ist es.

0
Serkan Koch