Php betiğini daemon işlemi olarak çalıştır


154

Ben daemon süreci (talimatlar için bekleyin ve şeyler yapmak) olarak bir php komut dosyası çalıştırmak gerekir. cron işi benim için yapmayacak çünkü talimat gelir gelmez harekete geçilmesi gerekiyor. PHP'nin bellek yönetimi sorunları nedeniyle gerçekten daemon süreçleri için en iyi seçenek olmadığını biliyorum, ancak çeşitli nedenlerden dolayı bu durumda PHP kullanmak zorundayım. Daemon ( http://libslack.org/daemon ) adlı libslack tarafından bir araçla karşılaştım, bu daemon süreçlerini yönetmeme yardımcı oluyor gibi görünüyor, ancak son 5 yılda herhangi bir güncelleme olmadı, bu yüzden davam için uygun diğer alternatifler. Herhangi bir bilgi gerçekten takdir edilecektir.


2
lütfen cevabımı kontrol et. teşekkürler
Henrik P. Hessel


1
Bu yazı geldi gonzalo123.com/2010/05/23/... ben hem rahatlatıcı ve kararlı olduğunu inanıyoruz.
Teson

O ilgisi çok kolay systemd
LeonanCarvalho

Yanıtlar:


167

Php betiğinizi komut satırından (örneğin bash) kullanarak başlatabilirsiniz.

nohup php myscript.php &

&arka planda süreci koyar.

Düzenleme:
Evet, bazı dezavantajları var, ancak kontrol etmek mümkün değil mi? Bu açıkça yanlış.
Basit bir kill processiddurduracak. Ve hala en iyi ve en basit çözüm.


Terminal varsa, işlem ÇIKMAZ. Bu yüzden "nohup" komutu var. Ben yıllardır sadece bu gibi tüm sunucularda daemon olarak bir PHP script kullanıyorum. Daha iyi bir çözüm olabilir, ancak bu en hızlı çözümdür.
CDR

27
Bu, başarısız olursa arka plan programını yeniden başlatmaz ve arka plan programını yönetmenin kolay bir yolu yoktur.
Phil Wallach

6
Burada söylenenlere katılıyorum - bu kötü bir çözüm. Birkaç nedenden dolayı bir init betiği oluşturmanız gerekir: 1) Init betiği başlangıçta otomatik olarak başlatılır 2) Daemon'u start / stop / restart komutlarıyla yönetebilirsiniz. Servefault'dan bir örnek: serverfault.com/questions/229759/…
Simian

1
hey millet ... bana öyle geliyor nohupve &aynı şeyi yapıyor: başlatılan süreci kabuğun mevcut intantından ayırmak. Neden ikisine de ihtiyacım var? Sadece yapamaz mıyım php myscript.php &yoksa nohup myscript.php?? Teşekkürler
nourdine

1
Komut dosyası stdout'a yazarsa (echo veya var_dump aracılığıyla), bu bilgileri aşağıdaki gibi bir günlük dosyasıyla yakalayabilirsiniz:nohup php myscript.php > myscript.log &
Mischa

167

Başka bir seçenek de Upstart'ı kullanmaktır . Başlangıçta Ubuntu için geliştirildi (ve varsayılan olarak onunla birlikte geliyor), ancak tüm Linux dağıtımları için uygun olması amaçlanıyor.

Bu yaklaşım Süpervizör ve arka plan programlarına benzer , çünkü sistem açılışında arka plan programını otomatik olarak başlatır ve komut dosyası tamamlandığında yeniden doğar.

Nasıl kurulur:

Adresinde yeni bir komut dosyası oluşturun /etc/init/myphpworker.conf. İşte bir örnek:

# 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

Daemon'unuzu başlatma ve durdurma:

sudo service myphpworker start
sudo service myphpworker stop

Daemon'unuzun çalışıp çalışmadığını kontrol edin:

sudo service myphpworker status

Teşekkürler

Bu tekniği öğrendiğim Kevin van Zonneveld'e çok teşekkürler .


2
bunu seviyorum. Sadece merak ediyorum, birden fazla eşzamanlı işçi bulundurmak mümkün mü? Bir işçinin artık yeterli olmadığı sorunum var.
Manuel

1
bu sistem başlangıcında otomatik olarak çalışacak mı?
slier

2
Sudo "hizmet myppworker başlangıç" benim için işe yaramadı. Ben "sudo start myphpworker" kullandım ve mükemmel çalışıyor
Matt Sich

3
@Pradeepta Çünkü yazı bir hata var - Tam olarak ne emin değilim (ve bunu test etmedim), ama ben sudo service myphpworker start/stop/statussadece /etc/init.duptart hizmet olmayan hizmetlerle çalışır düşünüyorum . @ matt-sich doğru söz dizimini açığa çıkardı. Başka bir seçenek, arka plan işleme ve deamonizasyona izin veren Gearman veya Resque kullanmaktır.
ckm

3
Ubuntu'nun kendisi upstart yerine systemd kullanmaya geçiyor
Kzqai

72

Yeni systemd ile bir servis oluşturabilirsiniz.

Örneğin, içinde bir dosya veya simge bağlantısı oluşturmanız gerekir /etc/systemd/system/. myphpdaemon.service ve bunun gibi bir içerik yerleştirin, myphpdaemon hizmetin adı olacaktır:

[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

Komutu kullanarak hizmetleri başlatabilir, durumu alabilir, yeniden başlatabilir ve durdurabilirsiniz.

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

PHP betiği çalışmaya devam etmek için bir tür "döngü" olmalıdır.

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

Çalışma örneği:

[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

PHP rutininizin bir döngüde (diggest gibi) bir kez yürütülmesi gerekiyorsa, doğrudan PHP yerine systemd hizmet dosyasına çağrılmak için bir kabuk veya bash betiği kullanabilirsiniz, örneğin:

#!/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

Eğer değiştirmelisiniz bu seçimini yaparsanız KillMode için mixedişlemlere, bash (ana) ve PHP (çocuk) öldürülebilir.

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

This method also is effective if you're facing a memory leak.

Not: "myphpdaemon.service" öğenizi her değiştirdiğinizde `` systemctl daemon-reload '' komutunu çalıştırmanız gerekir, ancak bunu yapmazsanız endişelenmeyin, gerektiğinde uyarılacaktır.


7
Yetersiz cevap. + 1'im var.
Gergely Lukacsy

2
Muhteşem. Cevapları da yüreklendirebilseydik, çünkü bu sayfaya gömülmemelidir.
Justin

1
systemctl status <your_service_name> -lÇıktıyı kontrol etmelisiniz , size neler olduğuna dair bir ipucu verecektir.
LeonanCarvalho

1
@LeandroTupone MySQL ve Memcached, hizmet bağımlılıklarının nasıl kullanılacağının bir göstergesiydi.
LeonanCarvalho

3
Bu, şimdi 2019 olduğu gibi kabul edilen cevabın yerini almalı.
baharat

47

UNIX Ortamında Gelişmiş Programlamanın bir kopyasını alabiliyorsanız . Bölüm 13'ün tamamı arka plan programlamaya ayrılmıştır. Örnekler C'dir, ancak ihtiyacınız olan tüm işlevin PHP'de sarmalayıcıları vardır (temelde pcntl ve posix uzantıları).

Birkaç kelimeyle - bir daemon yazmak (bu sadece * nix tabanlı işletim sistemlerinde mümkündür - Windows hizmetleri kullanır) şu şekildedir:

  1. umask(0)İzin sorunlarını önlemek için arayın .
  2. fork() ve ebeveynin çıkışını sağlayın.
  3. Arayın setsid().
  4. Kurulum sinyali işleme SIGHUP(genellikle bu yok sayılır veya yapılandırmayı yeniden yüklemek için arka plana sinyal vermek için kullanılır) ve SIGTERM(işlemin zarif bir şekilde çıkmasını söylemek için).
  5. fork() tekrar ve ebeveyn çıkışı.
  6. Geçerli çalışma dizinini ile değiştirin chdir().
  7. fclose() stdin, stdoutVe stderrve bunlara yazmayın. Doğru yol, bunları ya /dev/nullda bir dosyaya yönlendirmektir , ancak PHP'de bunu yapmanın bir yolunu bulamadım. Kabuğu kullanarak onları yönlendirmek için arka plan programını başlattığınızda mümkündür (bunu nasıl yapacağınızı kendiniz öğrenmeniz gerekir, bilmiyorum :).
  8. İşini yap!

Ayrıca, PHP kullandığınız için, döngüsel referanslar için dikkatli olun, çünkü PHP çöp toplayıcısının PHP 5.3'ten önce bu referansları toplamanın bir yolu yoktur ve işlem sonunda çökene kadar bellek sızıntısı yapar.


1
Bilgi için teşekkürler. Lbslack'ın daemon programı, sizin gibi tüm hazırlık çalışmalarını hemen hemen yapıyor. Şimdilik başka iyi alternatifler bulana kadar buna bağlı kalacağım.
Beier

1
Bu yazı bulundu, stdin vb kapatmak için başarısız bir berbat eski uygulama içine kopyalamak ve yapıştırmak için beklenen kod, hayal kırıklığına uğradım. : p
ThiefMaster

1
Neden (5) çatal ()?
TheFox

Benim için çalıştı - harika iş!
Gautam Sharma

Gelecekte iki kez çatallanmayı isteyen okuyucular için: stackoverflow.com/questions/881388/… - TL; DR: Zombileri önler.
Ghedipunk

24

Çok sayıda PHP arka plan programı çalıştırıyorum.

PHP'nin bunu yapmak için en iyi (veya iyi bir dil) olmadığı konusunda hemfikirim, ama daemonlar web'e bakan bileşenlerle kodu paylaşıyor, bu yüzden genel olarak bizim için iyi bir çözüm.

Bunun için daemontools kullanıyoruz. Akıllı, temiz ve güvenilirdir. Aslında bunu tüm cinlerimizi çalıştırmak için kullanıyoruz.

Bunu http://cr.yp.to/daemontools.html adresinden kontrol edebilirsiniz .

EDIT: Hızlı bir özellik listesi.

  • Arka plan programı yeniden başlatıldığında otomatik olarak başlatılır
  • Arıza durumunda otomatik olarak yeniden başlat
  • Rollover ve budama dahil olmak üzere günlük tutma sizin için yapılır
  • Yönetim arayüzü: 'svc' ve 'svstat'
  • UNIX dostu (belki herkes için bir artı değil)

Ayrıca depolardan, örneğin apt!
Kzqai

14

Yapabilirsin

  1. nohupHenrik'in önerdiği gibi kullanın .
  2. screenPHP programınızı içinde düzenli bir işlem olarak kullanın ve çalıştırın. Bu size kullanmaktan daha fazla kontrol sağlar nohup.
  3. Böyle bir daemoniser kullanın http://supervisord.org/ (Python diliyle yazıldığı ancak herhangi bir komut satırı programı daemonise ve size onu yönetmek için bir uzaktan kumanda verebilir).
  4. Emil'in önerdiği gibi kendi daemonise paketleyicinizi yazın, ancak IMO'yu abarttı.

En basit yöntemi (bence ekran) tavsiye ederim ve daha fazla özellik veya işlevsellik istiyorsanız, daha karmaşık yöntemlere geçin.


Benzer bir denetim yapılandırması sağlayabilir misiniz?
Alix Axel

11

Bu sorunu çözmenin birden fazla yolu vardır.

Özellikleri bilmiyorum ama belki PHP sürecini tetiklemek için başka bir yolu var. Örneğin, bir SQL veritabanındaki olaylara dayalı olarak kodun çalıştırılması gerekiyorsa, komut dosyanızı yürütmek için bir tetikleyici ayarlayabilirsiniz. PostgreSQL altında bunu yapmak gerçekten çok kolay: http://www.postgresql.org/docs/current/static/external-pl.html .

Dürüst olmak gerekirse, en iyi bahsinizin nohup kullanarak bir Damon süreci yaratmak olduğunu düşünüyorum. nohup, kullanıcı oturumu kapattıktan sonra bile komutun yürütülmeye devam etmesine izin verir:

nohup php myscript.php &

Ancak çok ciddi bir sorun var. Dediğin gibi PHP'nin bellek yöneticisi tam bir çöp, bir script sadece birkaç saniye yürütüyor ve sonra var olduğu varsayımıyla inşa edildi. PHP betiğiniz yalnızca birkaç gün sonra GIGABYTES belleği kullanmaya başlayacaktır. Ayrıca, php betiğinizi böyle öldürür ve yeniden doğurur her 12 veya 24 saat çalışan bir cron betiği oluşturmanız gerekir:

killall -3 php
nohup php myscript.php &

Ama senaryo bir işin ortasında olsaydı? Öldürmek -3 bir kesinti, CLI üzerinde bir ctrl + c yapmakla aynı. Php betiğiniz bu kesmeyi yakalayabilir ve PHP pcntl kütüphanesini kullanarak incelikle çıkabilir: http://php.oregonstate.edu/manual/en/function.pcntl-signal.php

İşte bir örnek:

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

$ Lock'un arkasındaki fikir PHP betiğinin fopen ("dosya", "w"); Dosyada yalnızca bir işlemin yazma kilidi olabilir, bu nedenle bunu kullanarak PHP betiğinizin yalnızca bir kopyasının çalıştığından emin olabilirsiniz.

İyi şanslar!




3

Son zamanlarda PHP betiklerini cin olarak çalıştırma sorununa çapraz platform çözümüne (Windows, Mac ve Linux) ihtiyacım vardı. Kendi C ++ tabanlı çözümümü yazarak ve ikili dosyalar yaparak sorunu çözdüm:

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

Linux için tam destek (sysvinit üzerinden), aynı zamanda Windows NT hizmetleri ve Mac OSX launchd.

Sadece Linux'a ihtiyacınız varsa, burada sunulan diğer çözümlerden birkaçı yeterince iyi çalışır ve lezzete bağlı olarak. Sysvinit betikleri için geri dönüşleri olan bu günlerde Upstart ve systemd de var. Ancak PHP kullanımının yarısı, doğada çapraz platform olmasıdır, bu nedenle dilde yazılan kod, her yerde olduğu gibi çalışma şansına sahiptir. Sistem hizmetleri gibi belirli harici yerel işletim sistemi düzeyindeki yönler resme girdiğinde eksiklikler ortaya çıkmaya başlar, ancak çoğu komut dosyası dilinde bu sorunu yaşarsınız.

Burada PHP kullanıcı ülkesinde önerdiği gibi sinyal yakalamaya çalışmak iyi bir fikir değildir. Belgeleri pcntl_signal()dikkatlice okuyun ve PHP'nin sinyalleri, süreçler (nadiren sinyaller) tarafından nadiren görülen bir şey için bir grup döngüyü çiğneyen oldukça hoş olmayan yöntemler (özellikle 'keneler') kullanarak hızlı bir şekilde öğreneceksiniz. PHP'de sinyal işleme de sadece POSIX platformlarında zar zor kullanılabilir ve PHP sürümüne göre destek farklıdır. Başlangıçta iyi bir çözüm gibi geliyor, ancak gerçekten yararlı olmaktan oldukça yetersiz.

PHP, zaman ilerledikçe bellek sızıntısı sorunları hakkında da iyileşiyor. Hala dikkatli olmanız gerekiyor (DOM XML ayrıştırıcısı hala sızıntı eğilimi gösteriyor) ancak nadiren bu gün kaçak süreçleri görüyorum ve PHP hata izleyicisi eskilere kıyasla oldukça sessiz.


1

Diğerlerinin de belirttiği gibi, PHP'yi bir daemon olarak çalıştırmak oldukça kolaydır ve tek bir komut satırı kullanılarak yapılabilir. Ancak asıl sorun, onu çalışmaya devam ettirmek ve yönetmek. Aynı problemi bir süre önce yaşadım ve zaten çok sayıda çözüm bulunmasına rağmen, çoğunun çok fazla bağımlılığı var veya kullanımı zor ve temel kullanımlar için uygun değil. Ben PHP cli komut dosyaları da dahil olmak üzere herhangi bir süreci / uygulamayı yönetebilirsiniz bir kabuk komut dosyası yazdı. Uygulamayı başlatmak için bir cronjob olarak ayarlanabilir ve uygulamayı içerecek ve yönetecektir. Tekrar çalıştırılırsa, örneğin aynı cronjob aracılığıyla, uygulamanın çalışıp çalışmadığını kontrol eder, eğer varsa, sadece çıkar ve önceki örneğinin uygulamayı yönetmeye devam etmesine izin verir.

Github'a yükledim, kullanmaktan çekinmeyin: https://github.com/sinasalek/EasyDeamonizer

EasyDeamonizer

Uygulamanızı izlemeniz yeterlidir (başlat, yeniden başlat, günlük, monitör vb.). uygulamanızın düzgün çalıştığından emin olmak için genel bir komut dosyası. Kasıtlı olarak tüm yan etkilerini önlemek ve komut dosyasını olabildiğince basit ve açık tutmak için pid / lock dosyasının işlem adını kullanır, böylece EasyDaemonizer yeniden başlatıldığında bile her zaman çalışır. Özellikleri

  • Uygulamayı ve isteğe bağlı olarak her başlatma için özelleştirilmiş bir gecikmeyi başlatır
  • Yalnızca bir örneğin çalıştığından emin olur
  • CPU kullanımını izler ve tanımlanan eşiğe ulaştığında uygulamayı otomatik olarak yeniden başlatır
  • Herhangi bir nedenle durdurulursa EasyDeamonizer'ı cron üzerinden çalışacak şekilde ayarlama
  • Etkinliğini günlüğe kaydeder

1

Emil Ivaov cevap genişletme , php STDIN, STDOUT VE STDERROR kapatmak için aşağıdakileri yapabilirsiniz

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');

Temelde standart akışları kapatırsınız, böylece PHP'nin yazacak bir yeri kalmaz. Aşağıdaki fopençağrılar standart ES'yi olarak ayarlar /dev/null.

Ben web ötesinde PHP - Rob Aley kitabından okudum



0

pm2'yi buradan kontrol edebilirsiniz, http://pm2.keymetrics.io/

ilgileneceğiniz php betiğinize koymak worker.sh gibi bir ssh dosyası oluşturun.

worker.sh

php /path/myscript.php

Daemon Start

pm2 start worker.sh

Şerefe, işte bu.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.