Чи корисно використовувати "while true" для збереження сценарію в живих?


19

Я просто стрибаю в unix з іншого світу і хотів дізнатися, чи є

while true
do
  /someperlscript.pl
done

Сам скрипт perl внутрішньо має дисертацію папок / файлів, яка виконується при зміні файлів у цільовому місці.

Це ( while true) гарна ідея? Якщо ні, то який переважний надійний підхід?

ТІА

EDIT: Оскільки, схоже, це викликало неабиякий інтерес, ось повний сценарій. Сам скрипт perl переглядає каталог, використовуючи інструмент для перегляду файлів. Отримавши нові файли (вони надходять через rsync), він підбирає новий та обробляє його. Тепер вхідні файли можуть бути пошкодженими (не вимагайте .., що надходять з малинового пі), і іноді процес може не впоратися з цим. Я точно не знаю чому, тому що ми ще не в курсі всіх сценаріїв.

АЛЕ - якщо процес з якоїсь причини виходить з ладу, ми хочемо, щоб він був запущений і працював із наступним файлом, оскільки наступний файл абсолютно не пов'язаний з попереднім, що, можливо, спричинило помилку.

Зазвичай я б використав якийсь вилов усіх і обернув весь код навколо нього, щоб він НІКОЛИ не збоїв. Але не був впевнений у перл.

З того, що я зрозумів, використовувати щось на кшталт нагляду - це хороший підхід для цього.


9
Це Linux чи UNIX? Якщо це Linux, ви можете перевірити inotifyAPI, щоб уникнути напруженого циклу, який очікує змін файлів у вашому цільовому каталозі.
roaima

Її linux, ubuntu
Abhinav Gujjar

Якщо ви знаєте, що файл хороший до того, як він покине pi, тоді ви можете просто запустити контрольну суму типу md5 або sha1 і надіслати його разом із своїм файлом. Тоді одержувач дізнається, чи отримав він поганий файл, перш ніж спробує його обробити. Якщо ви цього не знаєте, то ви все одно можете створити якісь часткові або блокові контрольні суми або щось подібне у вашому файлі даних, що гарантує цілісність даних, щоб ви могли перевіряти справи, перш ніж переходити до процесу, який може вийти з ладу. Унція профілактики ...
Джо

Відповіді:


21

Це залежить від швидкості повернення сценарію perl. Якщо він швидко повертається, ви можете вставити невелику паузу між виконанням, щоб уникнути завантаження процесора, наприклад:

while true
do
  /someperlscript.pl
  sleep 1
done

Це також запобіжить зависання процесора, якщо скрипт не буде знайдено або вийде з ладу негайно.

Цикл також може бути краще реалізований у самому скрипті perl, щоб уникнути цих проблем.

Редагувати:

Як ви писали цикл, єдиною метою є перезапуск сценарію perl, якщо він вийде з ладу, кращим підходом було б його реалізувати як моніторингову службу, але точний спосіб зробити це залежно від ОС. Напр .: Solaris smf, Linux systemd або перезапуск на базі хронів.


10
Ви можете зробити, while sleep 1; do ...щоб зберегти справжній дзвінок.
Рафаель Аренс

4
@RaphaelAhrens Дійсно, хоча це трохи змінить початкову поведінку. Замінник until ! sleep 1; do ...; doneвсе одно збереже цей вбудований виклик під час негайного запуску сценарію.
jlliagre

4
Повністю погоджуєтесь, що гарячого циклу слід уникати, коли ви збираєтесь це робити, коли ви збираєтесь це робити. Також погодьтеся, що керований подіями сценарій (inotify та ін.) Був би кращим рішенням. Але використання циклу в той час не є суттєвим злом, обов'язково, якщо це не безмежно і гаряче. Я думаю, що важливіше питання, мабуть, стосується того, чому сценарій perl виходить з ладу і потрібно його перезапустити.
Крейг

2
Краще : sleep 1& /someperlscript.pl; wait.
user23013

2
@EliahKagan Добре помічений. TBH, я ніколи не використовую untilінструкцію, я переплутав її з гіпотетичним do/untilциклом, який не існує в оболонці.
jlliagre

13

Інші відповіді щодо використання inotifyє правильними, але не є відповіддю на це питання.

Контролер процесів, такий як supervisord, upstartабо runit, призначений саме для проблеми перегляду та перезапуску служби, якщо вона виходить з ладу.

Ваш дистрибутив, ймовірно, має вбудований керівник процесів.


11

while trueчудово, як конструкція загального призначення «петля назавжди». Як говорять інші відповіді, тіло циклу не повинно бути порожнім або стати порожнім завдяки команді всередині циклу, яка не працює.

Якщо ви використовуєте Linux, можливо, ви хочете скористатися такою командою inotifywait, яка робить whileцикл набагато простішим:

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

Тут inotifywaitкоманда буде сидіти і чекати, коли відбудеться подія файлової системи (у цьому прикладі, коли файли в каталог записуються). У цей момент він успішно виходить і тіло циклу виконується. Потім він знову повертається до очікування. Оскільки inotifywaitкоманда чекає, що в каталозі щось станеться, це набагато ефективніше, ніж постійно опитувати каталог.


`(apt-get або yum) встановіть inotify-tools` +1 круто!
JJoao

4

Перемістіть час 1 на сценарій perl (За пропозицією @roaima)

#!/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
Це не відповідає вимозі перезапуску, якщо сценарій виходить з ладу або вбивається з якоїсь причини.
jlliagre

@jlliagre, дякую за коментар. У відповіді я не бачу чітких специфікацій передбачуваної поведінки після аварії чи вбивства. Це, очевидно, цікаве і актуальне питання. На даний момент я буду простою (якщо сценарій загинув або був убитий, залишайтеся мертвим :)
JJoao

@jlliagre Саме для цього є винятки. Але Perl може виявитися не найбільш підходящим вибором у такому випадку, оскільки він не підтримує механізм винятку. Просто здогадка. Найкраще буде перенести скрипт на мову, яка підтримує винятки. Все, звичайно, залежить, наскільки велика робота з перенесення.

@Nasha, в Perl, з обробниками сигналів, змінними помилок, Tyr :: Tiny тощо, ми можемо це зробити! ... але - я ненавиджу обробку винятків та відновлення помилок: вони ніколи не завершені ...
JJoao

1
@JJoao Я погоджуюся з вами щодо фактів, що відновлення помилок рідко буває повним. Звичайно, розробник повинен охопити всі можливі випадки. Так є і з PLC в індустріальному світі, тому це повинно бути цілком можливо ;-).

3

Коли ваш сценарій Perl призначений постійно працювати, навіщо використовувати конструкцію в той час? Коли Perl не вдається з огляду на якусь серйозну проблему, новий сценарій perl, запущений на той час, може вийти з ладу так само важко. Знову-знову-і-так.
якщо ви дійсно хочете, щоб ваш perl почався заново, розгляньте crontab та сценарій, який спочатку перевіряє запущені екземпляри. Таким чином ваш сценарій навіть буде запущений після перезавантаження.


2

Взагалі використання проблем не виникає, while trueоскільки це крихітний тест, який виконується лише після припинення сценарію perl. Майте на увазі, що залежно від того, який варіант Linux / Unix ви використовуєте, сценарій може бути припинений при виході з системи. У такому випадку розгляньте можливість використання циклу в скрипті та зателефонуйте до нього nohupта покладіть його на другий план, тобтоnohup myscript &

Якщо скрипт perl закінчується занадто часто і викликає завантаження процесора, це завантаження підлягає скрипту perl, а не while true.

Дивіться також man nohupдеталі.


Єдина проблема - потенціал для гарячого циклу, який сприяє використанню процесора. Тож я повністю згоден із тим, щоб увімкнути сплячий дзвінок всередині циклу, щоб приборкати його.
Крейг

2

Якщо ви хочете керувати процесом, ви можете заглянути в менеджера процесів, щоб зробити це.

У багатьох останніх системах ви можете використовувати systemd для контролю своїх процесів (що є однією з переваг systemd над класичними init-скриптами). Якщо ваш дистрибутив на вибір не використовує systemd, ви можете використовувати daemontools або monit .


monє простою альтернативою, якщо пихата величезність моніту та системності турбує вас так само, як і мене.
Анко

2

whileЦикл дійсно не дуже гарна ідея. Тут немає втечі - вона просто працює вічно - статично . Будь-яка кількість речей може змінитися в оточенні, і це не вплине - і це може бути погано.

Наприклад, якщо whileоновлений виконуваний файл оболонки, відповідальний за цей цикл, ядро ​​не зможе звільнити дисковий простір для старої версії до тих пір, поки цей сценарій не завершиться, оскільки йому потрібно підтримувати дескриптор, поки він працює. І це справедливо для будь-яких файлів, які оболонка може бути відкрита з будь-якої причини запустити цикл - всі вони будуть утримуватися відкритими цим whileциклом так довго, як він працює - назавжди.

І якщо, не дай бог, десь в оболонці протікає пам'ять, в якій працює цей цикл - навіть у саму хвилину - він просто продовжить протікати - статично . Він буде створюватися безперевірно, і єдиний прийом - насильно вбити його, а потім запустити його знову, щоб зробити те саме пізніше.

Це дійсно не так, як слід налаштовувати фоновий процес - принаймні, не на мою думку. Натомість, як я думаю, має бути точка скидання - оновлення сценарію та його стану. Найпростіший спосіб зробити це за допомогою exec. Ви можете замінити поточний процес на новий - зберігаючи той самий PID -, але все одно запустите новий процес.

Наприклад, якщо ваш perlскрипт повинен повернути true після того, як він успішно обробив модифікацію файлу в деякому контрольованому каталозі:

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

... або щось подібне. Щось, що дозволяє основній техніці за циклом оновлюватись раз у раз.


1

Я підтримав кілька таких відповідей, але інстинктивно відчуваю найтепліші почуття до відповіді @ WalterA. Ну, я робив, поки не створив власну відповідь ...

Особисто я схильний би оновити скрипт Perl, щоб він писав описовий запис у журналі про помилку і надсилав попередження адміністратору.

Якщо сценарій Perl покликаний продовжувати працювати, чекаючи подій зміни з файлової системи, чому він не працює?

Якщо це не вдається, чому ви турбуєтесь про те, щоб запустити його в сценарій, щоб нескінченно його перезапустити?

Якщо виникла проблема з конфігурацією або якась неполадка, яка спричиняє переривання сценарію Perl, просто перезавантажте його знову і знову, швидше за все, змусити його раптово не почати працювати.

Ви знаєте визначення божевілля, правда? (роблячи те саме і знову і знову, очікуючи іншого результату). Просто кажу. ;-)


ха-ха, я знаю, я знаю. але ви знаєте - реальний світ смокче. У будь-якому випадку - причина полягає в тому, що він обробляє файли, а деякі файли можуть навіть не передаватися правильно. Ми ще не знаємо різноманітності причин, які можуть вийти з ладу. Я бачу вашу думку щодо реєстрації помилки, але мені все одно знадобиться резервне копіювання, щоб обробити наступний файл через щось на зразок нагляду
Абхінав Гуджар

Якщо ви можете спіймати винятки, ви можете записати їх у систему, а потім продовжувати обробку та навіть повертатися назад та періодично повторювати невдалі файли? Можливо, невдалий файл був заблокований іншим користувачем або процесом, коли ви намагалися його обробити і т. Д.
Крейг,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.