Exécuter le script php comme processus de démon

j'ai besoin d'exécuter un script php comme processus de démon (attendre les instructions et faire des choses). cron job ne le fera pas pour moi parce que des mesures doivent être prises dès que les instructions arrivent. Je sais que PHP n'est pas vraiment la meilleure option pour les processus démon en raison de problèmes de gestion de la mémoire, mais pour diverses raisons, je dois utiliser PHP dans ce cas. Je suis tombé sur un outil de libslack appelé Daemon ( http://libslack.org/daemon ) il semble m'aider à gérer les processus de démon, mais il n'y a pas eu de mises à jour au cours des 5 dernières années, donc je me demande si vous connaissez d'autres alternatives adaptées à mon cas. Toute information sera vraiment appréciée.

133
demandé sur Darryl Hein 2010-01-10 13:06:50

12 réponses

vous pouvez démarrer votre script php depuis la ligne de commande (i.e. bash) en utilisant

nohup php myscript.php &

le & place votre processus à l'arrière-plan.

Edit:

Oui, Il ya quelques inconvénients, mais pas possible de contrôler? C'est tout simplement faux.

Un simple kill processid l'arrêtera. Et c'est toujours la meilleure et la solution la plus simple.

153
répondu Henrik P. Hessel 2010-01-19 06:46:18

une autre option est d'utiliser Upstart . Il a été développé à L'origine Pour Ubuntu (et est livré avec lui par défaut), mais est destiné à être adapté pour tous les Linux distros.

cette approche est similaire à Supervisord et daemontools , en ce qu'elle démarre automatiquement le démon sur le démarrage du système et répond à l'achèvement du script.

comment l'installer:

crée un nouveau fichier de script à /etc/init/myphpworker.conf . Voici un exemple:

# 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

Démarrer et arrêter votre démon:

sudo service myphpworker start
sudo service myphpworker stop

vérifiez si votre démon est en cours d'exécution:

sudo service myphpworker status

Merci

un grand merci à Kevin van Zonneveld , où j'ai appris cette technique.

143
répondu Jonathan 2013-05-16 20:05:53

si vous pouvez-grab une copie de programmation avancée dans L'environnement UNIX . L'ensemble du chapitre 13 est consacré à la programmation démon. Les exemples sont en C, mais toutes les fonctions dont vous avez besoin ont des wrappers en PHP (essentiellement les extensions pcntl et posix ).

en quelques mots-écrire un démon (cela n'est possible que sur *nix basé sur OS-es - Windows utilise des services) est comme ceci:

  1. Appel umask(0) pour éviter les problèmes d'autorisation.
  2. fork() et faites sortir le parent.
  3. appel setsid() .
  4. Setup signal de traitement de SIGHUP (généralement ignoré ou utilisé pour signaler au démon de recharger sa configuration) et SIGTERM (pour indiquer au processus de quitter gracieusement.)
  5. fork() encore une fois et avoir la sortie parent.
  6. modifier la directive de travail actuelle avec chdir() .
  7. fclose() stdin , stdout et stderr et ne leur écrivez pas. La façon correcte est de les rediriger vers /dev/null ou un fichier, mais je n'ai pas pu trouver un moyen de le faire en PHP. Il est possible, lorsque vous lancez le démon de redirigez - les en utilisant le shell (vous devrez trouver vous-même comment faire, Je ne sais pas :).
  8. Faites votre travail!

aussi, puisque vous utilisez PHP, soyez prudent pour les références cycliques, puisque le collecteur de déchets PHP, Avant PHP 5.3, n'a aucun moyen de recueillir ces références et le processus va fuite de mémoire, jusqu'à ce qu'il se brise éventuellement.

45
répondu Emil Ivanov 2012-01-15 21:42:57

avec le nouveau systemd vous pouvez créer un service (sur la base de rhel linux).

Vous devez créer un fichier ou un lien dans /etc/systemd/system/ , par exemple. myphpdaemon.service et placer un contenu comme celui-ci, myphpdaemon sera le nom du service:

[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

vous pourrez démarrer, obtenir le statut, redémarrer et arrêter les services en utilisant la commande

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

le script PHP doit avoir une sorte de" boucle " pour continuer à tourner.

<?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
        }
    }
}

exemple pratique:

[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

si votre PHP doit être exécuté une fois dans un cycle (comme un diggest), vous pouvez utiliser un script shell ou bash pour être invoqué dans le fichier de service systemd au lieu de PHP directement, par exemple:

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

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

si vous choisissez cette option vous devez changer le KillMode à mixed de processus, bash(principal) et php(enfant) être tué.

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

Note: chaque fois que vous changez votre "myphpdaemon.de service" vous devez run `systemctl démon-reload", mais ne vous inquiétez pas si vous ne le faites, il sera lorsque vous y êtes invité est nécessaire.

35
répondu LeonanCarvalho 2018-08-22 13:29:52

j'exécute un grand nombre de démons PHP.

je suis d'accord avec vous que PHP n'est pas le meilleur (ou même un bon) langage pour faire cela, mais les daemons partagent le code avec les composants qui font face au web, donc dans l'ensemble c'est une bonne solution pour nous.

nous utilisons des daemontools pour cela. Il est intelligent, propre et fiable. En fait, nous l'utilisons pour gérer tous nos démons.

vous pouvez le vérifier à http://cr.yp.to/daemontools.html .

EDIT: une liste rapide de fonctionnalités.

  • démarre automatiquement le démon en redémarrage
  • redémarrez automatiquement dameon en cas de panne
  • L'exploitation forestière est manipulée pour vous, y compris le retournement et la taille
  • interface de gestion: 'svc' et 'svstat'
  • Unix friendly (pas un plus pour tout le monde peut-être)
23
répondu Phil Wallach 2011-12-19 01:28:11

Vous pouvez

  1. utilisez nohup comme Henrik l'a suggéré.
  2. utilisez screen et exécutez votre programme PHP comme un processus régulier à l'intérieur de cela. Cela vous donne plus de contrôle que d'utiliser nohup .
  3. utilisez un daemoniser comme http://supervisord.org / (il est écrit en Python mais peut démoniser n'importe quel programme en ligne de commande et vous donner une télécommande pour le gérer).
  4. Ecrivez votre propre emballage de démonise comme Emil l'a suggéré, mais C'est exagéré IMO.

je recommande la méthode la plus simple (écran à mon avis) et puis si vous voulez plus de fonctionnalités ou de fonctionnalités, passer à des méthodes plus complexes.

14
répondu Noufal Ibrahim 2010-01-19 07:09:02

Il y a plus d'une façon de résoudre ce problème.

Je ne sais pas les détails, mais il y a peut-être un autre moyen de déclencher le processus PHP. Par exemple, si vous avez besoin du code pour exécuter basé sur des événements dans une base de données SQL, vous pouvez configurer un déclencheur pour exécuter votre script. C'est vraiment facile à faire sous PostgreSQL: http://www.postgresql.org/docs/current/static/external-pl.html .

honnêtement, je pense que votre mieux le pari est de créer un processus Damon en utilisant nohup. nohup permet à la commande de continuer à exécuter, même après que l'utilisateur s'est déconnecté:

nohup php myscript.php &

il y a cependant un problème très grave. Comme vous l'avez dit, le gestionnaire de mémoire de PHP est un déchet complet, il a été construit en partant de l'hypothèse qu'un script n'exécute que quelques secondes et qu'il existe ensuite. Votre script PHP commencera à utiliser des gigaoctets de mémoire après seulement quelques jours. Vous devez également créer un script cron qui s'exécute toutes les 12 ou peut-être 24 heures qui tue et re-produit votre script php comme ceci:

killall -3 php
nohup php myscript.php &

mais si le script était au milieu d'un travail? Bien tuer -3 est une interruption, c'est la même chose que faire un ctrl+c sur le CLI. Votre script php peut saisir cette interruption et sortir avec élégance en utilisant la bibliothèque PCNTL PHP: http://php.oregonstate.edu/manual/en/function.pcntl-signal.php

voici un exemple:

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

L'idée derrière l' $lock est que le script PHP peut ouvrir un fichier avec fopen("fichier","w");. Un seul processus peut avoir un verrouillage d'écriture sur un fichier, donc en utilisant ceci vous pouvez vous assurer qu'une seule copie de votre script PHP est en cours d'exécution.

Bonne Chance!

11
répondu rook 2011-12-19 01:30:54

Kevin van Zonneveld a écrit un très bel article détaillé sur ce , dans son exemple il fait usage du System_Daemon paquet de poire (dernière date de sortie le 2009-09-02).

10
répondu Alix Axel 2010-01-15 15:19:21

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

il s'agit d'une bibliothèque de démons orientée objet. Il a un support intégré pour des choses comme la journalisation et la récupération d'erreurs, et il a un support pour créer des travailleurs d'arrière-plan.

6
répondu Shane H 2013-02-16 00:30:34

j'ai récemment eu besoin d'une solution multiplateforme (Windows, Mac et Linux) au problème de l'exécution de scripts PHP en tant que démons. J'ai résolu le problème en écrivant ma propre solution basée sur C++ et en faisant des binaires:

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

prise en charge complète de Linux (via sysvinit), mais aussi des Services Windows NT et Mac OSX launchd.

si vous avez juste besoin de Linux, alors un quelques-unes des autres solutions présentées ici fonctionnent assez bien et, en fonction de la saveur. Il y a aussi Upstart et systemd de nos jours, qui ont des retombées sur les scripts sysvinit. Mais la moitié du point de L'utilisation de PHP est qu'il est de nature multiplateformes, de sorte que le code écrit dans la langue a une assez bonne chance de travailler partout comme-est. Les déficiences commencent à apparaître lorsque certains aspects natifs externes au niveau de L'OS entrent dans l'image tels que les services système, mais vous obtiendrez ce problème avec la plupart des langages de script.

tenter de capter des signaux comme quelqu'un ici suggéré dans PHP userland n'est pas une bonne idée. Lisez attentivement la documentation sur pcntl_signal() et vous apprendrez rapidement que PHP gère les signaux en utilisant des méthodes plutôt désagréables (spécifiquement, 'ticks') qui rongent un tas de cycles pour quelque chose rarement vu par les processus (i.e. les signaux). La gestion des signaux en PHP est également à peine disponible sur les plateformes POSIX et le support diffère selon les la version de PHP. Cela ressemble d'abord à une solution décente, mais elle est loin d'être vraiment utile.

PHP a également été de mieux en mieux sur les problèmes de fuite de mémoire que le temps progresse. Il faut encore faire attention (L'analyseur DOM XML a tendance à fuir encore) mais je vois rarement des processus en fuite de nos jours et le traceur de bogues PHP est assez silencieux par rapport à L'époque de yore.

3
répondu CubicleSoft 2016-06-11 21:59:57

comme d'autres l'ont déjà mentionné, exécuter PHP en tant que démon est assez facile, et peut être fait en utilisant une seule ligne de commande. Mais le vrai problème est de le maintenir en marche et de le gérer. J'ai eu le même problème il y a un certain temps et bien qu'il y ait beaucoup de solutions déjà disponibles, la plupart d'entre elles ont beaucoup de dépendances ou sont difficiles à utiliser et ne conviennent pas aux usages de base. J'ai écrit un script shell qui peut gérer n'importe quel processus/application, y compris les scripts PHP cli. Il peut être défini comme un cronjob pour démarrer l'application et contiendra l'application et la gérer. Si elle est exécutée à nouveau, par exemple via la même cronjob, elle vérifie si l'application est en cours d'exécution ou non, si elle le fait, elle sort tout simplement et laisse son instance précédente continuer à gérer l'application.

Je l'ai téléchargé sur github, n'hésitez pas à l'utiliser : https://github.com/sinasalek/EasyDeamonizer

EasyDeamonizer

veille simplement sur votre application (démarrage, redémarrage, log, monitor, etc.). un script générique pour s'assurer que votre application fonctionne correctement. Intentionnellement, il utilise le nom de processus Instaread de fichier pid / lock pour prévenir tous ses effets secondaires et de garder le script aussi simple et aussi stirghward que possible, de sorte qu'il fonctionne toujours même lorsque EasyDaemonizer lui-même est redémarré. Caractéristiques

  • délai personnalisé pour chaque démarrage
  • S'assure qu'une seule instance est en cours d'exécution
  • surveille L'utilisation CPU et redémarre automatiquement l'application lorsqu'elle atteint le seuil défini
  • réglage de EasyDeamonizer pour exécuter via cron pour l'exécuter à nouveau si elle est arrêtée pour une raison quelconque
  • enregistre son activité
1
répondu Sina Salek 2016-05-20 11:11:05

j'ai écrit et déployé un simple PHP-daemon, le code est en ligne ici""

https://github.com/jmullee/PhpUnixDaemon

Caractéristiques: privilège de faire tomber, de traitement du signal, de l'exploitation forestière

je l'ai utilisé dans une file d'attente de gestionnaire (cas d'utilisation: déclencher une opération longue à partir d'une page web, sans faire la page de génération de php attendre, c'est à dire le lancement d'une opération asynchrone) https://github.com/jmullee/PhpIPCMessageQueue

0
répondu jmullee 2017-07-30 14:30:52