스크립트를 생생하게 유지하기 위해“진정한”을 사용하고 있습니까?


19

나는 다른 세계에서 유닉스로 뛰어 들었고,

while true
do
  /someperlscript.pl
done

perl 스크립트 자체에는 내부에 파일이 대상 위치에서 변경 될 때 실행되는 폴더 / 파일 감시자가 있습니다.

이것이 while true좋은 생각입니까? 그렇지 않은 경우 선호되는 강력한 접근 방법은 무엇입니까?

티아

편집 : 이것은 상당한 관심을 불러 일으킨 것으로 보이므로 여기에 전체 시나리오가 있습니다. perl 스크립트 자체는 파일 감시자를 사용하여 디렉토리를 감시합니다. 새 파일을 받으면 (rsync를 통해 도착) 새 파일을 가져 와서 처리합니다. 이제 들어오는 파일이 손상되었을 수 있습니다 (요청하지 마십시오. 라즈베리 파이에서 나옴). 때로는 프로세스에서 처리하지 못할 수도 있습니다. 우리는 아직 모든 시나리오를 알지 못하기 때문에 이유를 정확히 알지 못합니다.

그러나 어떤 이유로 프로세스가 실패하면 다음 파일이 오류를 일으킨 이전 파일과 완전히 관련이 없으므로 프로세스가 시작되어 다음 파일을 처리하기를 원합니다.

일반적으로 나는 일종의 catch를 사용하고 전체 코드를 감싸서 충돌하지 않도록했습니다. 그러나 펄은 확실하지 않았다.

내가 이해 한 바에 따르면 supervisord와 같은 것을 사용하는 것이 좋습니다.


9
이것이 Linux입니까 아니면 UNIX입니까? Linux 인 경우 inotify대상 디렉토리에서 파일이 변경 될 때까지 대기중인 루프를 피할 수 있도록 API 를 점검 할 수 있습니다.
roaima

그것의 리눅스, 우분투
Abhinav Gujjar

파이를 떠나기 전에 파일이 양호하다는 것을 알고 있다면 md5 또는 sha1과 같은 체크섬을 실행하여 파일과 함께 보낼 수 있습니다. 그러면 수신자는 파일을 처리하기 전에 잘못된 파일이 있는지 알 수 있습니다. 이를 모르는 경우에도 데이터 무결성을 보장하는 데이터 파일에 일종의 부분 또는 블록 체크섬 또는 이와 유사한 것을 구축 할 수 있으므로 실패 할 수있는 프로세스를 수행하기 전에 진행 상황을 확인할 수 있습니다. 예방의 온스 ...
Joe

답변:


21

이것은 펄 스크립트가 얼마나 빨리 반환되는지에 달려 있습니다. 빠르게 리턴되면 다음과 같이 CPU로드를 피하기 위해 실행 사이에 작은 일시 정지를 삽입 할 수 있습니다.

while true
do
  /someperlscript.pl
  sleep 1
done

또한 스크립트를 찾지 못하거나 즉시 충돌하는 경우 CPU 호그를 방지합니다.

루프는 이러한 문제를 피하기 위해 perl 스크립트 자체에서 더 잘 구현 될 수 있습니다.

편집하다:

루프 전용 목적을 썼을 때 perl 스크립트가 충돌하는 경우 다시 시작하는 것이 더 나은 방법은 모니터링 된 서비스로 구현하는 것이지만 OS를 사용하는 정확한 방법입니다. 예 : Solaris smf, Linux 시스템 또는 cron 기반 재시작 기.


10
당신은 while sleep 1; do ...진정한 전화를 저장 할 수 있습니다.
Raphael Ahrens 2016 년

4
@RaphaelAhrens 실제로 초기 동작이 약간 변경 될 수 있습니다. 대체 프로그램 until ! sleep 1; do ...; done은 스크립트를 즉시 시작하면서 해당 내장 호출을 계속 저장합니다.
jlliagre

4
이 작업을 수행하려면 루프 내부에서 수면 호출 을 사용하여 핫 루프를 피해야한다는 데 전적으로 동의합니다 . 또한 이벤트 중심 스크립트 (inotify 등)가 더 나은 솔루션이라는 데 동의합니다. 그러나 while 루프를 사용하는 것이 무한하고 뜨겁지 않은 한 본질적으로 악한 것은 아닙니다. 더 중요한 문제는 아마도 perl 스크립트가 실패하고 다시 시작 해야하는 이유를 다루는 것이라고 생각합니다.
Craig

2
더 나은 : sleep 1& /someperlscript.pl; wait.
user23013

2
@EliahKagan 잘 발견했다. TBH, 나는 until명령을 사용 do/until하지 않으며, 쉘에 존재하지 않는 가상 루프 와 혼동했습니다 .
jlliagre 2016

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 cool!
JJoao

4

while 1을 펄 스크립트로 옮기십시오 (@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, 의견 주셔서 감사합니다. 답에 따르면 충돌 또는 종료 후 의도 한 동작에 대한 명확한 사양이 표시되지 않습니다. 이것은 분명 흥미롭고 관련된 질문입니다. 잠시 동안 나는 간단하게 할 것이다 (스크립트가 죽거나 죽었다면
죽어라

@jlliagre 예외가 있습니다. 그러나 Perl은 예외 메커니즘을 지원하지 않기 때문에 이러한 경우에 가장 적합한 선택이 아닐 수 있습니다. 그냥 추측. 예외를 지원하는 언어로 스크립트를 이식하는 것이 가장 좋습니다. 물론 포팅 작업의 규모에 달려 있습니다.

@Nasha, Perl에서 신호 처리기, 오류 변수, Tyr :: Tiny 등으로 할 수 있습니다! ... 그러나-예외 처리 및 오류 복구가
싫습니다.

1
@JJoao 오류 복구가 거의 완료되지 않았다는 사실에 동의합니다. 물론 모든 가능한 경우를 다루는 것은 개발자의 책임입니다. 산업계의 PLC에서도 마찬가지이므로 결국 가능해야합니다. ;-).

3

perl 스크립트가 항상 계속 실행되도록하려면 왜 while 구성을 사용합니까? 펄이 심각한 문제를보고 실패 할 때, 새로운 펄 스크립트는 while에 의해 시작된 것처럼 아주 힘들어 질 수 있습니다. 또 다시 또 다시.
펄을 실제로 다시 시작하려면 crontab과 인스턴스 실행을 먼저 확인하는 스크립트를 고려하십시오. 이렇게하면 재부팅 후에도 스크립트가 시작됩니다.


2

일반적으로 while true펄 스크립트가 종료 된 후에 만 ​​실행되는 작은 테스트이기 때문에 문제가 없습니다 . 사용중인 Linux / Unix 변형에 따라 로그 오프시 스크립트가 종료 될 수 있습니다. 이 경우 스크립트에서 루프를 사용하여 호출하고 백그라운드 nohup로 넣으십시오.nohup myscript &

perl 스크립트가 너무 자주 종료되고이로드보다 CPU로드가 발생하는 경우 while true.

자세한 내용은 참조 man nohup하십시오.


유일한 문제는 CPU 사용률을 높이는 핫 루프의 가능성입니다. 그래서 나는 루프 안에 잠들기를 호출하여 그것을 길들이는 것에 전적으로 동의합니다.
Craig

2

프로세스를 관리하려는 경우 프로세스 관리자를 조사하십시오.

최신 시스템이 많은 경우 systemd 를 사용 하여 프로세스를 모니터링 할 수 있습니다 (이는 init-script보다 고전적인 systemd의 이점 중 하나임). 선택한 배포판에서 systemd를 사용하지 않으면 daemontools 또는 monit을 사용할 수 있습니다 .


mon방대한 양의 monit과 시스템이 저만큼이나 귀찮게한다면 간단한 대안입니다.
Anko

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 스크립트가 중단되면 단순히 다시 시작해도 갑자기 작동하지 않을 수 있습니다.

당신은 광기의 정의를 알고 있습니까? (같은 결과를 반복해서 반복하면서 다른 결과를 기대합니다). 그냥 말하면 ;-)


haha- 알아요 그러나 당신은 알고 있습니다-실제 세계는 짜증납니다. 어쨌든-그 이유는 파일을 처리하고 일부 파일이 제대로 전송되지 않기 때문입니다. 우리는 아직 실패 할 수있는 다양한 이유를 모른다. 오류를 기록하는 것에 대한 요점을 알지만 감독자와 같은 것을 통해 다음 파일을 처리하기 위해 여전히 백업해야합니다.
Abhinav Gujjar

예외를 잡을 수 있으면 예외를 기록한 후 처리를 계속하고 심지어 실패한 파일을 다시 시도 할 수 있습니까? 실패한 파일은 처리하려고 할 때 다른 사용자 나 프로세스에 의해 잠겨있을 수 있습니다.
Craig
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.