Rasgele bir komut dosyasını unix'te nasıl daemonize edebilirim?


94

Rastgele, genel bir komut dosyasını veya komutu bir arka plan programına dönüştürebilen bir daemonizer istiyorum .

Ele almak istediğim iki yaygın durum var:

  1. Sonsuza kadar çalışması gereken bir senaryom var. Ölürse (veya yeniden başlatıldığında), yeniden başlatın. Aynı anda iki kopya çalışmasına izin vermeyin (bir kopyanın zaten çalışıp çalışmadığını tespit edin ve bu durumda başlatmayın).

  2. Sonsuza kadar tekrar tekrar yürütmek istediğim (çalıştırmalar arasında kısa bir duraklama ile) basit bir komut dosyam veya komut satırı komutum var. Yine, komut dosyasının iki kopyasının aynı anda çalışmasına izin vermeyin.

Elbette 2. durumda komut dosyası etrafında bir "while (doğru)" döngüsü yazmak ve ardından 1. durum için bir çözüm uygulamak önemsizdir, ancak daha genel bir çözüm 2. durumu doğrudan çözecektir çünkü bu durum 1'deki komut dosyası için geçerli kuyu (script gerçekten eğer komut şimdiye elbette (ölmek üzere tasarlanmamıştır eğer sadece kısa veya hiç duraklama isteyebilir gelmez sonra asla ölmez duraklama yok aslında olsun)).

Çözümün, örneğin mevcut komut dosyalarına dosya kilitleme kodu veya PID kaydı eklemeyi içermemesi gerektiğini unutmayın.

Daha spesifik olarak, çalıştırabileceğim bir "daemonize" programı istiyorum

% daemonize myscript arg1 arg2

veya örneğin,

% daemonize 'echo `date` >> /tmp/times.txt'

bu, times.txt dosyasına eklenen artan bir tarih listesi tutacaktır. (Daemonize edilecek argüman (lar) yukarıdaki 1. durumda olduğu gibi sonsuza kadar çalışan bir betik ise, o zaman daemonize yine de doğru olanı yapacak ve gerektiğinde yeniden başlatacaktır.) O zaman yukarıdaki gibi bir komutu .login dosyama koyabilirim. ve / veya saat başı veya dakikası (beklenmedik bir şekilde ölmesi konusunda ne kadar endişelendiğime bağlı olarak).

Not: daemonize betiğinin, arka planda çalıştığı komut dizesini hatırlaması gerekir, böylece aynı komut dizesi yeniden daemonize edilirse, ikinci bir kopya başlatmaz.

Ayrıca, çözüm ideal olarak hem OS X hem de linux üzerinde çalışmalıdır, ancak biri veya diğeri için çözümler memnuniyetle karşılanır.

DÜZENLEME: ile çağırmanız gerekiyorsa sorun değil sudo daemonize myscript myargs.

(Bunun tamamen yanlış olduğunu düşünüyorsam veya hızlı ve kirli kısmi çözümler varsa, bunu da duymak isterim.)


Not: Yararlı olması durumunda, işte python'a özgü benzer bir soru.

Ve benzer bir soruya verilen bu yanıt, keyfi bir yazıyı hızlıca ve kirli bir şekilde şeytanlaştırmak için yararlı bir deyim gibi görünen şeyi içerir:


1
Bkz serverfault.com/questions/311593/... saf kabuk versiyonu için
w00t

Yanıtlar:


93

Nohup ve & operatörünü kullanarak Unix'teki herhangi bir yürütülebilir dosyayı daemonize edebilirsiniz:

nohup yourScript.sh script args&

Nohup komutu, komut dosyanızı öldürmeden kabuk oturumunuzu kapatmanıza izin verirken, komut dosyanızı arka plana yerleştirir, böylece oturumunuza devam etmek için bir kabuk istemi alırsınız. Bununla ilgili tek küçük sorun, standart çıkış ve standart hatanın her ikisi de ./nohup.out'a gönderilir, bu nedenle, bu malikanede birkaç komut dosyası başlatırsanız, bunların çıktıları iç içe geçecektir. Daha iyi bir komut şöyle olacaktır:

nohup yourScript.sh script args >script.out 2>script.error&

Bu, standart olarak seçtiğiniz dosyaya ve standart hatayı seçtiğiniz farklı bir dosyaya gönderir. Hem standart çıkış hem de standart hata için yalnızca bir dosya kullanmak istiyorsanız, şunu bize yapabilirsiniz:

nohup yourScript.sh script args >script.out 2>&1 &

2> & 1, kabuğa standart hatayı (dosya tanımlayıcısı 2) standart çıkışla (dosya tanımlayıcısı 1) aynı dosyaya yeniden yönlendirmesini söyler.

Bir komutu yalnızca bir kez çalıştırmak ve ölürse yeniden başlatmak için şu komut dosyasını kullanabilirsiniz:

#!/bin/bash

if [[ $# < 1 ]]; then
    echo "Name of pid file not given."
    exit
fi

# Get the pid file's name.
PIDFILE=$1
shift

if [[ $# < 1 ]]; then
    echo "No command given."
    exit
fi

echo "Checking pid in file $PIDFILE."

#Check to see if process running.
PID=$(cat $PIDFILE 2>/dev/null)
if [[ $? = 0 ]]; then
    ps -p $PID >/dev/null 2>&1
    if [[ $? = 0 ]]; then
        echo "Command $1 already running."
        exit
    fi
fi

# Write our pid to file.
echo $$ >$PIDFILE

# Get command.
COMMAND=$1
shift

# Run command until we're killed.
while true; do
    $COMMAND "$@"
    sleep 10 # if command dies immediately, don't go into un-ctrl-c-able loop
done

İlk argüman, kullanılacak pid dosyasının adıdır. İkinci argüman ise komuttur. Ve diğer tüm argümanlar komutun argümanlarıdır.

Bu komut dosyasını yeniden başlat.sh olarak adlandırırsanız, şöyle adlandırırsınız:

nohup restart.sh pidFileName yourScript.sh script args >script.out 2>&1 &

Harika; teşekkür ederim. Yeniden başlatmada bir gecikme seçeneği olup olmayacağını merak ediyorum. Ya da sadece bununla birlikte kullanmak daha iyi olabilir: stackoverflow.com/questions/555116/…
dreeves

4
Bu yalnızca SIGHUP'ı işler, ele alınması gereken başka (normalde) ölümcül sinyaller vardır.
Tim Post

Bu betiği geliştirmenin başka bir yolu, muhtemelen $ PIDFILE'ı arg olarak belirtilmesini gerektirmek yerine kendi başına yerleştirmek için iyi bir konum bulmasıdır. Kendinden sonra bile temizlemez! (a ile anlaşılır olmalıdır trap EXIT)
Steven Lu

Ayrıca kullanımı düşünün <içinde testbir ASCII karşılaştırma değil bir tamsayı karşılaştırmasıdır. Yine de işe yarayabilir, ancak hatalara yol açabilir.
Steven Lu

Düzeltmelerimi burada bu komut dosyasına gönderdim .
Steven Lu

34

Uzun cevap için özür dilerim (lütfen cevabımın şartnameyi nasıl etkilediğiyle ilgili yorumlara bakın). Kapsamlı olmaya çalışıyorum, böylece olabildiğince iyi bir ayağa sahipsin. :-)

Programları yükleyebiliyorsanız (kök erişiminiz varsa) ve betiğinizi arka plan programı yürütmesi için ayarlamak üzere bir defalık çalışma yapmaya istekliyseniz (yani, komut satırında çalıştırılacak komut satırı argümanlarını belirtmekten daha fazlasını içerir, ancak hizmet başına yalnızca bir kez yapılması gerekiyor), daha sağlam bir yöntemim var.

Daemontool kullanmayı içerir . Yazının geri kalanı daemontools kullanarak hizmetlerin nasıl kurulacağını açıklıyor.

İlk kurulum

  1. Daemontools nasıl kurulur bölümündeki talimatları izleyin . Bazı dağıtımlar (örneğin, Debian, Ubuntu) zaten bunun için paketlere sahiptir, bu yüzden onu kullanın.
  2. Adlı bir dizin oluşturun /service. Yükleyicinin bunu zaten yapmış olması gerekir, ancak yalnızca doğrulayın veya manuel olarak kuruyorsanız. Bu konumu svscanbootbeğenmezseniz , betiğinizde değiştirebilirsiniz , ancak çoğu daemontool kullanıcısı kullanmaya alışkındır ve kullanmazsanız /servicekafaları karışacaktır .
  3. Standart kullanmayan init(yani kullanmayan /etc/inittab) Ubuntu veya başka bir dağıtım kullanıyorsanız, aranacak inittabdüzenleme svscanbootiçin önceden yüklenmiş olanı bir temel olarak kullanmanız gerekecektir init. Zor değil, ancak initişletim sisteminizin kullandığı ayarları nasıl yapılandıracağınızı bilmeniz gerekiyor . svscanboothizmet aramanın svscanana işini yapan, çağıran bir betiktir ; ondan denir initböylece initherhangi bir nedenle ölürse onu yeniden düzenleyecektir.

Hizmet başına kurulum

  1. Her hizmetin , hizmetle ilgili temizlik bilgilerini depolayan bir hizmet dizinine ihtiyacı vardır . Ayrıca, bu hizmet dizinlerini barındıracak bir konum da oluşturabilirsiniz, böylece hepsi tek bir yerde olur; genellikle kullanırım /var/lib/svscan, ancak herhangi bir yeni konum uygun olacaktır.
  2. Genelde servis dizinini kurmak için bir komut dosyası kullanıyorum , çok sayıda manuel tekrarlayan işi kaydetmek için. Örneğin,

    sudo mkservice -d /var/lib/svscan/some-service-name -l -u user -L loguser "command line here"
    

    some-service-namehizmetinize vermek istediğiniz ad nerede , userbu hizmeti loguserçalıştıracak kullanıcı ve kaydediciyi çalıştıracak kullanıcı. (Günlük kaydı biraz açıklanmıştır.)

  3. Hizmetinizin ön planda çalışması gerekir . Program arka planlarınız varsayılan olarak, ancak bunu devre dışı bırakma seçeneğine sahipse, bunu yapın. Programınızın arka planını devre dışı fghackbırakmanın bir yolu yoksa, okumaya devam edin , ancak bu bir değiş tokuşla gelir: artık kullanarak programı kontrol edemezsiniz svc.
  4. Düzen runbunu sağlamak için komut siz istediğiniz şeyi yapıyor. sleepHizmetinizin sık sık çıkmasını bekliyorsanız, üst tarafa bir arama yapmanız gerekebilir .
  5. Her şey doğru ayarlandığında /service, servis dizininize işaret ederek bir sembolik bağlantı oluşturun . (Servis dizinlerini doğrudan içine koymayın /service; bu, hizmetin svscansaatinden kaldırılmasını zorlaştırır .)

Kerestecilik

  1. Günlük tutmanın daemontools yolu, hizmetin günlük mesajlarını standart çıktıya yazmasını sağlamaktır (veya ile oluşturulan komut dosyalarını kullanıyorsanız standart hata mkservice); svscangünlük mesajlarının günlük kaydı hizmetine gönderilmesiyle ilgilenir.
  2. Günlük hizmeti, günlük mesajlarını standart girişten alır. Tarafından oluşturulan günlük hizmeti komut dosyası mkservice, log/maindizinde otomatik olarak döndürülen, zaman damgalı günlük dosyaları oluşturur . Mevcut günlük dosyası denir current.
  3. Günlük kaydı hizmeti, ana hizmetten bağımsız olarak başlatılabilir ve durdurulabilir.
  4. Günlük dosyalarını yönlendirmek tai64nlocal, zaman damgalarını insan tarafından okunabilir bir biçime çevirir. (TAI64N, nanosaniye sayımına sahip 64 bitlik bir atomik zaman damgasıdır.)

Kontrol hizmetleri

  1. svstatBir hizmetin durumunu almak için kullanın . Günlük kaydı hizmetinin bağımsız olduğunu ve kendi durumuna sahip olduğunu unutmayın.
  2. İle hizmetinizi (başlatma, durdurma, yeniden başlatma vb.) Kontrol edersiniz svc. Örneğin, hizmetinizi yeniden başlatmak için svc -t /service/some-service-name; -t"gönder SIGTERM" anlamına gelir .
  3. Mevcut diğer sinyaller arasında -h( SIGHUP), -a( SIGALRM), -1( SIGUSR1), -2( SIGUSR2) ve -k( SIGKILL) bulunur.
  4. Servisi azaltmak için kullanın -d. Ayrıca down, hizmet dizininde adlandırılmış bir dosya oluşturarak, bir hizmetin önyüklemede otomatik olarak başlamasını da önleyebilirsiniz .
  5. Servisi başlatmak için kullanın -u. Daha önce düşürmediğiniz sürece (veya otomatik başlamayacak şekilde ayarlamadıysanız) bu gerekli değildir.
  6. Süpervizörden çıkmasını istemek için şunları kullanın -x; genellikle -dhizmeti de sonlandırmak için kullanılır . Bu, bir hizmetin kaldırılmasına izin vermenin olağan yoludur, ancak önce hizmetin bağlantısını kaldırmanız gerekir /service, aksi svscantakdirde süpervizörü yeniden başlatır. Ayrıca, hizmetinizi bir günlük kaydı hizmetiyle ( mkservice -l) oluşturduysanız svc -dx /var/lib/svscan/some-service-name/log, hizmet dizinini kaldırmadan önce günlük kaydı denetçisinden (örneğin ) çıkmayı da unutmayın .

Özet

Artıları:

  1. daemontools, hizmetleri oluşturmak ve yönetmek için kurşun geçirmez bir yol sağlar. Sunucularım için kullanıyorum ve kesinlikle tavsiye ediyorum.
  2. Günlük kaydı sistemi, hizmetin otomatik yeniden başlatma özelliği gibi çok sağlamdır.
  3. Hizmetleri yazdığınız / ayarladığınız bir kabuk betiği ile başlattığı için, hizmetinizi istediğiniz gibi uyarlayabilirsiniz.
  4. Güçlü servis kontrol araçları: Herhangi bir sinyali bir servise gönderebilir ve servisleri güvenilir bir şekilde yukarı ve aşağı getirebilirsiniz.
  5. Hizmetlerinize temiz bir yürütme ortamı garanti edilir: Sağladıklarıyla aynı ortam, işlem sınırları vb. İle çalışırlar init.

Eksileri:

  1. Her hizmet biraz kurulum gerektirir. Neyse ki, bunun hizmet başına yalnızca bir kez yapılması gerekiyor.
  2. Hizmetler ön planda çalışacak şekilde ayarlanmalıdır. Ayrıca, en iyi sonuçlar için, syslog veya diğer dosyalar yerine standart çıktı / standart hatayı günlüğe kaydedecek şekilde ayarlanmaları gerekir.
  3. İşleri yapmanın daemontools yönteminde yeniyseniz, dik öğrenme eğrisi. Hizmetleri kullanarak yeniden başlatmanız gerekir svcve çalıştırma komut dosyalarını doğrudan çalıştıramazsınız (çünkü bu durumda bunlar süpervizörün kontrolü altında olmayacaklardır).
  4. Çok sayıda temizlik dosyası ve çok sayıda temizlik süreci. Her hizmetin kendi hizmet dizinine ihtiyacı vardır ve her hizmet, ölürse hizmeti otomatik olarak yeniden başlatmak için bir gözetmen işlemi kullanır. (Çok sayıda hizmetiniz varsa, işlem tablonuzda çok sayıda superviseişlem göreceksiniz .)

Dengede, daemontools'un ihtiyaçlarınız için mükemmel bir sistem olduğunu düşünüyorum. Nasıl kurulacağı ve sürdürüleceği ile ilgili soruları memnuniyetle karşılıyorum.


Cevabım şartnameyi nasıl belirledi: 1. Yinelemeleri ayarlamadığınız sürece (ve hizmetinizin arka planda çalışmadığı sürece), yinelemeler olmayacak şekilde hizmetleri kurmanız gerekir. 2. supervise, süpervizör, çıkan herhangi bir hizmeti yeniden başlatmaya özen gösterir. Yeniden başlatmalar arasında bir saniye bekler; bu sizin için yeterli zaman değilse, servis çalıştırma komut dosyasının en üstüne bir uyku koyun.
Chris Jester-Young

2a. supervisekendisi tarafından desteklenmektedir svscan, bu nedenle bir süpervizör ölürse, yeniden başlatılacaktır. 2b. svscantarafından desteklenir ve gerektiğinde initotomatik svscanolarak yeniden başlatılır . 2c. Herhangi initbir nedenle ölürseniz, yine de mahvolursunuz. :-P
Chris Jester-Young

Temizlik ile ilgili diğer soruları yanıtlamak için, daemontools sistemi, eskiyebilecekleri için PID dosyalarını kullanmaz. Bunun yerine, tüm süreç bilgileri belirli bir hizmeti destekleyen süpervizör tarafından saklanır. Süpervizör, hizmet dizininde araçların beğeneceği svstatve svcbirlikte çalışabileceği bir dizi dosya (ve FIFO) tutar .
Chris Jester-Young

3
SO'da ve genel olarak internette bunun gibi daha fazla gönderi olmalı. Sadece istenen etkiye nasıl ulaşılacağına dair bir tarif değil, tarifleri açıklama zahmetine giren bir tarif. Neden buna birden fazla olumlu oy veremiyorum? : |
skytreader

12

Sanırım denemek isteyebilirsin start-stop-daemon(8). /etc/init.dÖrnekler için herhangi bir Linux dağıtımındaki komut dosyalarına göz atın . Başlatılan işlemleri komut satırına veya PID dosyasına göre bulabilir, böylece komut dosyanız için bekçi olmak dışında tüm gereksinimlerinizi karşılar. Ancak her zaman, gerekirse betiğinizi yeniden başlatan başka bir daemon watchdog betiği başlatabilirsiniz.


Fedora'da henüz başlat-durdur-arka plan programı yoktur, bu nedenle ona bağlı betikler taşınabilir değildir. Bakınız: fedoraproject.org/wiki/Features/start-stop-daemon
Bengt

OSX kullanıcıları için sadece bir uyarı: start-stop-daemonorada da yok (10.9 itibariyle).
mklement0

@ mklement0 Pekala ... Yaklaşık 5 yılda çok şey değişti.
Alex B

Tanrım, zaman nasıl uçar. start-stop-daemonhala yaşıyor ve Linux üzerinde tekmeliyor; ama cevap okuduktan sonra stackoverflow.com/a/525406/45375 ben OSX kendi şeyi yapar fark: launchd.
mklement0

12

Daemonize'e bir göz atmalısınız . İkinci kopyanın algılanmasına izin verir (ancak dosya kilitleme mekanizmasını kullanır). Ayrıca farklı UNIX ve Linux dağıtımlarında da çalışır.

Uygulamanızı arka plan programı olarak otomatik olarak başlatmanız gerekiyorsa, uygun init komut dosyasını oluşturmanız gerekir.

Aşağıdaki şablonu kullanabilirsiniz:

#!/bin/sh
#
# mydaemon     This shell script takes care of starting and stopping
#               the <mydaemon>
#

# Source function library
. /etc/rc.d/init.d/functions


# Do preliminary checks here, if any
#### START of preliminary checks #########


##### END of preliminary checks #######


# Handle manual control parameters like start, stop, status, restart, etc.

case "$1" in
  start)
    # Start daemons.

    echo -n $"Starting <mydaemon> daemon: "
    echo
    daemon <mydaemon>
    echo
    ;;

  stop)
    # Stop daemons.
    echo -n $"Shutting down <mydaemon>: "
    killproc <mydaemon>
    echo

    # Do clean-up works here like removing pid files from /var/run, etc.
    ;;
  status)
    status <mydaemon>

    ;;
  restart)
    $0 stop
    $0 start
    ;;

  *)
    echo $"Usage: $0 {start|stop|status|restart}"
    exit 1
esac

exit 0

1
Doğru cevap için aday gibi görünüyor. Özellikle "tek örnek denetimi" düşünüldüğünde.
Martin Wickman

Bu mümkün olan en iyi cevap olabilir - emin değilim - ama öyle olduğunu düşünüyorsanız, soruda verdiğim spesifikasyonun neden yanlış olduğuna dair bir açıklama da ekleyebilir misiniz?
dreeves

Ben sevmiyorum killprocdurdurma bölümünde: Eğer diyelim ki, ran, bu bir süreç olsaydı java, killprocdiğer tüm Java süreçleri de öldürülmüş neden olacaktır.
Chris Jester-Young

1
/Etc/rc.d/init.d/functions adresinden daemonize yeni bir kabuktan ikiliyi başlatır: $ cgroup $ nice / bin / bash -c $corelimit >/dev/null 2>&1 ; $*Bu yüzden herhangi bir şeyi daemonize edeceğinden şüpheliyim ...
mbonnin

1
Bunun eski olduğunu biliyorum, ama bunu daha sonra bulan biri için ... bu doğru. yok /etc/init.d/functions tanımlanan "cin" değil aslında sizin için Artalanda. Bu süreç zaten bir kullanıcı, set güzel ve ulimit değerlerini, vb kurulmuştur, çalışıyorsa, onay cgroups yapmak için sadece bir sarıcı var değil sizin için süreci Artalanda. Bu hala senin kendi işin. :)
jakem

7

Daha önce bahsedildiği alternatif olarak daemonizeve daemontools, orada cin libslack paketinin komut.

daemon oldukça yapılandırılabilir ve otomatik yeniden başlatma, günlük kaydı veya pidfile işleme gibi tüm sıkıcı arka plan programlarını önemsiyor.


5

Özellikle OS X kullanıyorsanız, launchd'nin nasıl çalıştığına bir göz atmanızı öneririm. Komut dosyanızın çalıştığından emin olmak için otomatik olarak kontrol edecek ve gerekirse yeniden başlatacaktır. Aynı zamanda her türlü programlama özelliğini, vb. İçerir. Hem 1. hem de 2. gereksinimi karşılamalıdır.

Betiğinizin yalnızca bir kopyasının çalışabileceğinden emin olmak için, bir PID dosyası kullanmanız gerekir. Genelde /var/run/.pid 'ye, mevcut çalışan örneğin PID'sini içeren bir dosya yazarım. program çalıştığında dosya mevcutsa, dosyadaki PID'nin gerçekten çalışıp çalışmadığını kontrol eder (program çökmüş olabilir veya başka bir şekilde PID dosyasını silmeyi unutmuş olabilir). Eğer öyleyse, iptal edin. Değilse, çalışmaya başlayın ve PID dosyasının üzerine yazın.


5

Daemontools ( http://cr.yp.to/daemontools.html ), bunu yapmak için kullanılan, dj bernstein tarafından yazılmış, oldukça güçlü bir araç setidir. Bunu biraz başarıyla kullandım. İşin can sıkıcı yanı, komut dosyalarının hiçbirini çalıştırdığınızda görünür sonuç döndürmemesidir - sadece görünmez dönüş kodları. Ama bir kez çalıştığında kurşun geçirmez.


Evet, daemontools kullanan bir giriş yazacaktım. Kendi yazımı yazacağım, çünkü cevabımla çok daha kapsamlı olmayı umuyorum ve ödülü bu şekilde almayı umuyorum. Göreceğiz. :-)
Chris Jester-Young

3

İlk olsun createDaemon()gelen http://code.activestate.com/recipes/278731/

Ardından ana kod:

import subprocess
import sys
import time

createDaemon()

while True:
    subprocess.call(" ".join(sys.argv[1:]),shell=True)
    time.sleep(10)

Ooh, teşekkürler! Bunu biraz daha genel hale getirmek ister misiniz, böylece "foo arg1 arg2 deemonize" ve "daemonize 'foo arg1 arg2" yapabilir misiniz?
dreeves

Tamam, şimdi argümanlara katılacak - ancak argümanlarınızın içinde boşluk olmasını istiyorsanız onu değiştirmeniz gerekecektir.
Douglas Leeder

Teşekkürler Douglas! Yine de büyük bir kusur var: "daemonize foo" yu iki kez çalıştırmak, foo'nun iki kopyasını çalıştırmaya başlar.
dreeves

Biraz PID kayıt kodu ekleyebilirsiniz, ancak betiği yalnızca bir kez çalıştırmak en iyisi olabilir ...
Douglas Leeder

Bunun, tüm "daemonize" sarmalayıcı kavramı için temel olduğunu düşünüyorum. (Örneğin, her zaman çalıştığından emin olmak için onu saat başı veya dakika olarak çalıştırabilirim.) Bunu yanlış mı düşünüyorum? CreateDaemon bunu zaten bir şekilde garanti ediyor mu? Yeniden başlatmadan sonra ne olacak?
dreeves

1

Bu, boş bir dizine kopyalayıp deneyebileceğiniz bir örnekle tamamlanmış bir çalışma sürümüdür ( Getopt :: Long , File :: Spec , File :: Pid ve IPC :: System olan CPAN bağımlılıklarını kurduktan sonra : : Basit - hepsi oldukça standarttır ve herhangi bir bilgisayar korsanı için şiddetle tavsiye edilir: hepsini aynı anda yükleyebilirsiniz cpan <modulename> <modulename> ...).


keepAlive.pl:

#!/usr/bin/perl

# Usage:
# 1. put this in your crontab, to run every minute:
#     keepAlive.pl --pidfile=<pidfile> --command=<executable> <arguments>
# 2. put this code somewhere near the beginning of your script,
#    where $pidfile is the same value as used in the cron job above:
#     use File::Pid;
#     File::Pid->new({file => $pidfile})->write;

# if you want to stop your program from restarting, you must first disable the
# cron job, then manually stop your script. There is no need to clean up the
# pidfile; it will be cleaned up automatically when you next call
# keepAlive.pl.

use strict;
use warnings;

use Getopt::Long;
use File::Spec;
use File::Pid;
use IPC::System::Simple qw(system);

my ($pid_file, $command);
GetOptions("pidfile=s"   => \$pid_file,
           "command=s"   => \$command)
    or print "Usage: $0 --pidfile=<pidfile> --command=<executable> <arguments>\n", exit;

my @arguments = @ARGV;

# check if process is still running
my $pid_obj = File::Pid->new({file => $pid_file});

if ($pid_obj->running())
{
    # process is still running; nothing to do!
    exit 0;
}

# no? restart it
print "Pid " . $pid_obj->pid . " no longer running; restarting $command @arguments\n";

system($command, @arguments);

example.pl:

#!/usr/bin/perl

use strict;
use warnings;

use File::Pid;
File::Pid->new({file => "pidfile"})->write;

print "$0 got arguments: @ARGV\n";

Şimdi yukarıdaki örneği şu şekilde çağırabilirsiniz: ./keepAlive.pl --pidfile=pidfile --command=./example.pl 1 2 3ve dosya pidfileoluşturulacak ve çıktıyı göreceksiniz:

Pid <random number here> no longer running; restarting ./example.pl 1 2 3
./example.pl got arguments: 1 2 3

Doğru anladıysam, bunun tam olarak belirtilmeyeceğini düşünüyorum. Çözümünüzde (teşekkürler, btw!) Daemonize etmek istediğiniz program, PID'sini PID dosyasına yazacak şekilde değiştirilmelidir. Keyfi bir senaryoyu daemonize edebilecek bir yardımcı program umuyorum.
dreeves

@dreeves: evet, ancak bunun etrafında iki yol var: 1. keepAlive.pl (örneğin, example.pl) tarafından çağrılan komut dosyası, gerçek programı çalıştırmak için basitçe bir sarmalayıcı olabilir veya 2. keepAlive.pl, aktif sistem süreçleri (CPAN'ın Proc :: ProcessTable'ı ile) ilgili süreci ve onun pid'sini bulmaya çalışmak için).
Ether

1

Monit'i de deneyebilirsiniz . Monit, diğer hizmetleri izleyen ve raporlayan bir hizmettir. Esas olarak çalışma zamanı sorunları hakkında (e-posta ve sms yoluyla) bildirimde bulunmanın bir yolu olarak kullanılsa da, buradaki diğer önerilerin çoğunun savunduğu şeyi de yapabilir. Programları otomatik (yeniden) başlatabilir ve durdurabilir, e-posta gönderebilir, diğer komut dosyalarını başlatabilir ve alabileceğiniz bir çıktı günlüğü tutabilir. Ek olarak, sağlam belgeler olduğu için kurulumu ve bakımı kolay buldum.


1

Ölümsüz olmayı deneyebilirsiniz Bu bir * nix çapraz platform (OS agnostik) süpervizörüdür.

MacOS üzerinde hızlı bir deneme için:

brew install immortal

Eğer kullandığınız FreeBSD limanlarından veya pkg kullanarak:

pkg install immortal

For Linux ön derlenmiş ikilikleri indirerek veya kaynaktan: https://immortal.run/source/

Ya şu şekilde kullanabilirsiniz:

immortal -l /var/log/date.log date

Veya size daha fazla seçenek sunan bir yapılandırma YAML dosyasıyla, örneğin:

cmd: date
log:
    file: /var/log/date.log
    age: 86400 # seconds
    num: 7     # int
    size: 1    # MegaBytes
    timestamp: true # will add timesamp to log

Standart hata çıktısını ayrı bir dosyada tutmak isterseniz, aşağıdaki gibi bir şey kullanabilirsiniz:

cmd: date
log:
    file: /var/log/date.log
    age: 86400 # seconds
    num: 7     # int
    size: 1    # MegaBytes
stderr:
    file: /var/log/date-error.log
    age: 86400 # seconds
    num: 7     # int
    size: 1    # MegaBytes
    timestamp: true # will add timesamp to log

0

Diğer cevap üzerinde bir dizi iyileştirme yaptım .

  1. Bu betiğin stdout'u, komutun halihazırda çalıştırıldığını algılaması nedeniyle çıkmadıkça, tamamen alt öğesinden gelen standart çıktıdan oluşur.
  2. sonlandırıldığında pidfile'dan sonra temizler
  3. isteğe bağlı yapılandırılabilir zaman aşımı süresi (Herhangi bir pozitif sayısal bağımsız değişkeni kabul eder, adresine gönderir sleep)
  4. kullanım istemi -h
  5. tek komut yürütme yerine rastgele komut yürütme. Son arg VEYA kalan bağımsız değişkenler (son birden fazla argüman varsa) gönderilir eval, böylece bu komut dosyasına arka planda çalışmasını sağlamak için son argüman (veya sondaki argümanlar) olarak göndermek için bir dize olarak herhangi bir tür kabuk betiği oluşturabilirsiniz.
  6. -ltyerine ile yapılan bağımsız değişken sayısı karşılaştırmaları<

İşte senaryo:

#!/bin/sh

# this script builds a mini-daemon, which isn't a real daemon because it
# should die when the owning terminal dies, but what makes it useful is
# that it will restart the command given to it when it completes, with a
# configurable timeout period elapsing before doing so.

if [ "$1" = '-h' ]; then
    echo "timeout defaults to 1 sec.\nUsage: $(basename "$0") sentinel-pidfile [timeout] command [command arg [more command args...]]"
    exit
fi

if [ $# -lt 2 ]; then
    echo "No command given."
    exit
fi

PIDFILE=$1
shift

TIMEOUT=1
if [[ $1 =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
        TIMEOUT=$1
        [ $# -lt 2 ] && echo "No command given (timeout was given)." && exit
        shift
fi

echo "Checking pid in file ${PIDFILE}." >&2

#Check to see if process running.
if [ -f "$PIDFILE" ]; then
    PID=$(< $PIDFILE)
    if [ $? = 0 ]; then
        ps -p $PID >/dev/null 2>&1
        if [ $? = 0 ]; then
            echo "This script is (probably) already running as PID ${PID}."
            exit
        fi
    fi
fi

# Write our pid to file.
echo $$ >$PIDFILE

cleanup() {
        rm $PIDFILE
}
trap cleanup EXIT

# Run command until we're killed.
while true; do
    eval "$@"
    echo "I am $$ and my child has exited; restart in ${TIMEOUT}s" >&2
    sleep $TIMEOUT
done

Kullanım:

$ term-daemonize.sh pidfilefortesting 0.5 'echo abcd | sed s/b/zzz/'
Checking pid in file pidfilefortesting.
azzzcd
I am 79281 and my child has exited; restart in 0.5s
azzzcd
I am 79281 and my child has exited; restart in 0.5s
azzzcd
I am 79281 and my child has exited; restart in 0.5s
^C

$ term-daemonize.sh pidfilefortesting 0.5 'echo abcd | sed s/b/zzz/' 2>/dev/null
azzzcd
azzzcd
azzzcd
^C

Bu betiği farklı dizinlerden çalıştırırsanız, farklı pid dosyaları kullanabileceğine ve çalışan herhangi bir örneği algılamayacağına dikkat edin. Bir bağımsız değişken aracılığıyla sağlanan geçici komutları çalıştırmak ve yeniden başlatmak için tasarlandığından, bir şeyin daha önce başlatılıp başlatılmadığını bilmenin bir yolu yoktur, çünkü bunun aynı komut olup olmadığını kim söyleyebilir ? Bir şeyin yalnızca tek bir örneğini çalıştırma zorunluluğunu geliştirmek için duruma özel bir çözüm gereklidir.

Ayrıca, uygun bir arka plan programı olarak işlev görmesi için, diğer yanıtın da bahsettiği gibi (en azından) nohup kullanmalısınız. Sürecin alabileceği sinyallere direnç sağlamak için hiçbir çaba göstermedim.

Unutulmaması gereken bir diğer nokta da, bu betiği öldürmenin (eğer öldürülen başka bir komut dosyasından veya bir sinyalle çağrılmışsa) çocuğu öldürmede başarılı olamayacağıdır, özellikle de çocuk başka bir komut dosyasıysa. Bunun neden olduğundan emin değilim, ancak evalişleyiş biçimiyle ilgili bir şey gibi görünüyor , bu benim için gizemli. Bu nedenle, bu satırı, diğer cevapta olduğu gibi yalnızca tek bir komutu kabul eden bir şeyle değiştirmek akıllıca olabilir.

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.