Bir senaryoyu canlı tutmak için “while true” kullanmak iyi bir fikir midir?


19

Sadece farklı bir dünyadan unix'e atlıyorum ve

while true
do
  /someperlscript.pl
done

Perl betiğinin kendisinde dahili olarak dosyalar hedef konumda değiştirildiğinde çalıştırılan bir klasör / dosya izleyici vardır.

Bu ( while true) iyi bir fikir mi? Değilse, tercih edilen sağlam yaklaşım nedir?

TIA

EDIT: Bu oldukça ilgi çekici gibi görünüyor, işte tam senaryo. Perl betiğinin kendisi bir dosya izleyici kullanarak bir dizini izler. Yeni dosyalar aldıktan sonra (rsync ile gelirler), yeni dosyaları alır ve işler. Şimdi gelen dosyalar bozuk olabilir (sormayın .. bir ahududu pi geliyor) ve bazen süreç onunla başa olmayabilir. Nedenini tam olarak bilmiyorum, çünkü henüz tüm senaryoların farkında değiliz.

AMA - işlem herhangi bir nedenle başarısız olursa, bir sonraki dosyada hataya neden olabilecek bir öncekiyle tamamen alakasız olduğundan, işlemin çalışır durumda olmasını ve bir sonraki dosyayla ilgilenmesini istiyoruz.

Genellikle ben yakalamak bir tür kullanılmış ve ASLA çöküyor böylece etrafındaki tüm kodu sarılmış olurdu. Ama perl için emin değildi.

Anladığım kadarıyla, süpervizör gibi bir şey kullanmak bunun için iyi bir yaklaşım.


9
Bu Linux mu, UNIX mi? Linux inotifyise, hedef dizininizde dosyaların değişmesini bekleyen meşgul bir döngüden kaçınmak için API'yi kontrol etmek isteyebilirsiniz .
roaima

Its linux, ubuntu
Abhinav Gujjar

Dosyanın pi'den ayrılmadan önce iyi olduğunu biliyorsanız, md5 veya sha1 gibi bir sağlama toplamı çalıştırabilir ve bunu dosyanızla birlikte gönderebilirsiniz. Daha sonra alıcı, işlemeden önce kötü bir dosya olup olmadığını bilecektir. Bunu bilmiyorsanız, yine de veri bütünlüğünüzü garanti eden bir tür kısmi veya blok sağlama toplamı veya benzer bir şey oluşturabilirsiniz, böylece başarısız olabilen bir işleme başlamadan önce işleri kontrol edebilirsiniz. Bir ons önleme ...
Joe

Yanıtlar:


21

Bu perl betiğinin ne kadar hızlı döndüğüne bağlıdır. Hızlı bir şekilde geri dönerse, CPU yükünü önlemek için yürütmeler arasında küçük bir duraklama eklemek isteyebilirsiniz, örneğin:

while true
do
  /someperlscript.pl
  sleep 1
done

Bu, komut dosyası bulunmazsa veya hemen çökerse CPU domuzunu da önler.

Döngü ayrıca bu sorunları önlemek için perl betiğinin kendisinde daha iyi uygulanabilir.

Düzenle:

Döngünün yazdığı gibi, amaç kilitlendiğinde perl betiğini yeniden başlatmaktır, daha iyi bir yaklaşım izlenen bir hizmet olarak uygulamaktır, ancak bunu yapmanın kesin yolu işletim sistemine bağlıdır. Örneğin: Solaris smf, Linux systemd veya cron tabanlı bir yeniden başlatma.


10
while sleep 1; do ...Gerçek aramayı kaydetmek için yapabilirsiniz .
Raphael Ahrens

4
@RaphaelAhrens Gerçekten de bu ilk davranışı biraz değiştirecektir. Alternatif until ! sleep 1; do ...; done, komut dosyasını hemen başlatırken bu yerleşik aramayı yine de kaydeder.
jlliagre

4
Tamamen, bunu yapacağınız zaman döngü içinde bir uyku çağrısı ile bir sıcak döngü kaçınılması gerektiğini tamamen katılıyorum . Ayrıca, olay güdümlü bir komut dosyasının (inotify, et al) daha iyi bir çözüm olacağını kabul edin. Ancak while döngüsü kullanmak, sonsuz ve sıcak olmadıkça, zorunlu olarak kötü değildir. Bence daha önemli bir sorun muhtemelen neden perl betiğinin başarısız olduğu ve yine yeniden başlatılması gerekiyor.
Craig

2
Daha iyi: sleep 1& /someperlscript.pl; wait.
user23013

2
@EliahKagan İyi tespit edildi. TBH, untiltalimatı asla kullanmıyorum do/until, kabuğunda olmayan varsayımsal bir döngü ile karıştırdım .
jlliagre

13

Kullanmayla ilgili diğer cevaplar inotifydoğrudur, ancak bu sorunun cevabı değildir.

Bir proses amiri gibi supervisord, upstartya da runit, izliyor ve çökerse servisin yeniden başlatılması tam sorunu için tasarlanmıştır.

Dağıtımınız muhtemelen yerleşik bir süreç süpervizörü ile birlikte gelir.


11

while truegenel amaçlı bir "sonsuza kadar döngü" yapısı olarak iyidir. Diğer cevapların söylediği gibi, döngünün gövdesi boş olmamalı veya döngünün içindeki komut çalışmadığından boş kalmamalıdır.

Linux kullanıyorsanız inotifywait, whiledöngüyü çok daha basit hale getiren aşağıdaki gibi bir komut kullanmak isteyebilirsiniz :

while inotifywait -qqe modify "$DIRECTORY"
do
    process_the_directory "$DIRECTORY"
done

Burada, inotifywaitkomut oturur ve bir dosya sistemi olayının gerçekleşmesini bekler (bu örnekte, dizindeki dosyalar yazıldığında). Bu noktada, başarıyla çıkar ve döngünün gövdesi yürütülür. Daha sonra tekrar beklemeye geri döner. Çünkü inotifywaitkomut dizininde bir şeyler olmasını bekler, bu dizin sürekli yoklama çok daha verimli.


`(apt-get veya yum) inotify araçlarını yükleyin +1 harika!
JJoao

4

While 1'i perl betiğine taşı (@roaima önerisini takiben)

#!/usr/bin/perl

 use Linux::Inotify2;

 my $inotify = new Linux::Inotify2 or die "unable to inotify: $!";

 $inotify->watch ("Dir", IN_MODIFY, ## or in_{acess,create,open, etc...}
   sub { my $e = shift;
     my $name = $e->fullname;
     ## whatever 
     print "$name was modified\n" if $e->IN_MODIFY;
  });

 1 while $inotify->poll;

1
Komut dosyası çökerse veya herhangi bir nedenle öldürülürse, yeniden başlatma gereksinimini karşılamaz.
jlliagre

@jlliagre, yorum için teşekkürler. Cevapta, bir çarpışma veya öldürmeden sonra amaçlanan davranış için net bir şartname göremiyorum. Bu açıkça ilginç ve alakalı bir soru. Şimdilik basit tutacağım (senaryo öldüyse veya öldürüldüyse,
ölün

@jlliagre İstisnalar bunun içindir. Ancak Perl, istisna mekanizmasını desteklemediğinden böyle bir durumda en uygun seçim olmayabilir. Sadece bir tahmin. Komut dosyasını istisnaları destekleyen bir dile taşımak en iyisidir. Her şey elbette taşıma işinin ne kadar büyük olduğuna bağlıdır.

@Nasha, Perl'de, sinyal işleyicileri, hata değişkenleri, Tyr :: Tiny, vb. İle yapabiliriz! ... ama - İstisna işleme ve hata kurtarma nefret ediyorum: asla tamamlanmadı ...
JJoao

1
@JJoao Hata düzeltme işleminin nadiren tamamlandığı konusunda size katılıyorum. Elbette tüm olası durumları kapsamak geliştiriciye bağlıdır. Endüstri dünyasındaki PLC'lerle de öyle, bu yüzden sonuçta oldukça mümkün olmalı ;-).

3

Perl betiğinizin sürekli çalışmaya devam etmesi istendiğinde neden while yapısını kullanıyorsunuz? Perl ciddi bir sorun göz önüne alındığında başarısız olduğunda, süre ile başlayan yeni perl betiği de aynı şekilde çökebilir. Yine-ve-tekrar-ve-so-on.
perl'inizin gerçekten başlamasını istiyorsanız, crontab'ı ve önce çalışan örnekleri kontrol eden bir komut dosyasını düşünün. Bu şekilde komut dosyanız yeniden başlatıldıktan sonra bile başlayacaktır.


2

Genellikle while trueperl betiği sonlandırıldıktan sonra yürütülen küçük bir test olduğundan, kullanımda herhangi bir sorun yoktur . Hangi Linux / Unix varyantını kullandığınıza bağlı olarak komut dosyasının oturum kapatıldığında sonlandırılabileceğini unutmayın. Bu durumda, döngüyü bir komut dosyasında kullanmayı düşünün ve ile çağırın nohupve arka plana koyun.nohup myscript &

Perl betiği çok sık sonlanırsa ve CPU yüküne neden olursa, bu yük perl betiğine değil, perl betiğine karşı sorumludur while true.

Ayrıntılar için ayrıca man nohupbakınız.


Tek sorun, CPU kullanımını artıran bir sıcak döngü potansiyeli. Bu yüzden döngüyü içine uydurmak için uyku çağrısı koymaya tamamen katılıyorum.
Craig

2

Bir işlemi yönetmek istiyorsanız, bunu yapmak için bir süreç yöneticisine bakmak isteyebilirsiniz.

Birçok yeni sistemde, systemd'yi işlemlerinizi izlemek için kullanabilirsiniz (bu, systemd'nin klasik başlangıç ​​komut dosyalarına göre avantajlarından biridir). Seçim dağıtımınız systemd kullanmıyorsa, daemontools veya monit kullanabilirsiniz .


monbasit bir alternatif, eğer monit ve systemd'in ışıl ışıl gücü sizi benim kadar rahatsız ediyorsa.
Anko

2

whileDöngü gerçekten iyi bir fikir değildir. Orada kaçış yok - sadece sonsuza dek sürüyor - statik olarak . Çevrede çok sayıda şey değişebilir ve bu durum etkilenmez - ve bu kötü olabilir.

Örneğin, bu whiledöngüden sorumlu olan kabuk yürütülebilir dosyası yükseltilirse, çekirdek komut dosyası çıkıncaya kadar eski sürümün disk alanını serbest bırakamaz; çünkü tanımlayıcı çalıştığı sürece korumasını gerektirir. Ve bu, kabuğun döngüyü çalıştırmak için herhangi bir nedenden ötürü açık olabileceği tüm dosyalar için geçerlidir - hepsi bu whiledöngü tarafından çalıştığı sürece açık kalır - sonsuza kadar.

Ve eğer cennet yasaklarsa, kabuğun içinde o döngüyü çalıştıran herhangi bir yerde bellek sızıntısı olur - en fazla dakika bile - statik olarak sızmaya devam eder . Kontrol edilmeyecek ve tek başvuru, onu zorla öldürmek, sonra da daha sonra aynısını yapmak için yeniden başlatmak.

Bu gerçekten arka planlı bir süreci kurmanın yolu değil - en azından bence değil. Bunun yerine, düşündüğüm gibi, bir sıfırlama noktası olmalı - komut dosyasının ve durumunun yenilenmesi. Bunu yapmanın en kolay yolu exec. Sen yenisi ile mevcut süreci değiştirebilirsiniz - Aynı PID korurken - ama hala çalışan yeni işlem .

Örneğin, perlkomut dosyanız izlenen bazı dizinde bir dosya değişikliğini başarıyla gerçekleştirdikten sonra true değerini döndürürse:

#!/bin/sh
trap 'rm -rf -- "${ldir%%*.}"' 0 INT
_exec() case    $#      in
        (0)     exec env -  "PID=$$" "ldir=${TMPDIR:-/tmp}/." \
                            "$0" "$@";;
        (*)     export "$@" "boff=0" "lmt=30"
                exec        "$0" "$@";;
        esac
[ "$PID" = "$$" ] || _exec
[ -w "$ldir" ]  &&
case    $ldir   in
(*.)    until   mkdir -- "$ldir"
        do      :& ldir=$ldir$$$!
        done    2>/dev/null
;;
(*)     until   /someperlscript.pl ||
                [ "$((boff+=1))"  -ge "$lmt" ]
        do      [ -d "$ldir" ]     &&
                sleep "$boff"      || ! break
        done
;;esac  &&      _exec ldir PID

...ya da böyle bir şey. Döngünün arkasındaki temel makinelerin arada bir yenilenmesini sağlayan bir şey.


1

Bu cevaplardan birkaçını onayladım, ancak @ WalterA'nın cevabı için içgüdüsel olarak en sıcak hislerim var. Kendi cevabımı yaratana kadar yaptım ...

Şahsen, Perl betiğini hata hakkında açıklayıcı bir günlük girişi yazacak ve bir yöneticiye uyarı gönderecek şekilde güncelleme eğilimindeyim.

Perl betiğinin çalışmaya devam etmesi gerekiyorsa, dosya sisteminden değişiklik olayları beklenirse, neden başarısız oluyor?

Başarısız değilse, neden sonsuza kadar yeniden başlatmak için bir komut dosyasına sarmaktan endişeleniyorsunuz?

Perl betiğinin iptal edilmesine neden olan bir yapılandırma sorunu veya bozuk bir bağımlılık varsa, basitçe tekrar tekrar yeniden başlatmanın aniden çalışmaya başlaması muhtemel değildir.

Deliliğin tanımını biliyorsun, değil mi? (aynı şeyi tekrar tekrar yapmak, farklı bir sonuç beklemek). Sadece söylüyorum. ;-)


haha- Biliyorum, biliyorum. ama biliyorsun - gerçek dünya berbat. Her neyse - bunun nedeni dosyaları işlemesi ve bazı dosyaların düzgün bir şekilde iletilmemesidir. Başarısız olmasının çeşitli nedenlerini henüz bilmiyoruz. Hatayı günlüğe kaydetme hakkındaki görüşünüzü görüyorum, ancak yine de bir sonraki dosyayı süpervizör
Abhinav Gujjar

İstisnaları yakalayabilirseniz, bunları günlüğe kaydedip işlemeye devam edebilir ve hatta geri dönüp bazen başarısız dosyaları yeniden deneyebilirsiniz? Belki başarısız dosya, vb.
Craig
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.