[bash] 프로세스가 종료되면 프로세스를 다시 시작하기 위해 bash 스크립트를 작성하는 방법

대기열을 확인하고 각 항목에 대해 작업을 수행하는 Python 스크립트가 있습니다.

# checkqueue.py
while True:
  check_queue()
  do_something()

bash 스크립트가 실행 중인지 확인하고 그렇지 않은 경우 시작하는 bash 스크립트를 작성하는 방법 대략 다음 의사 코드 (또는 어쩌면 ps | grep? 와 같은 작업을 수행해야 함 ) :

# keepalivescript.sh
if processidfile exists:
  if processid is running:
     exit, all ok

run checkqueue.py
write processid to processidfile

나는 crontab에서 그것을 부를 것입니다 :

# crontab
*/5 * * * * /path/to/keepalivescript.sh



답변

PID 파일, 크론 또는 자녀가 아닌 프로세스를 평가하려는 다른 것을 피하십시오.

유닉스에서는 오직 당신의 자녀 만 기다릴 수있는 이유가 있습니다. 이 문제를 해결하려고 시도하는 모든 방법 (ps 구문 분석, pgrep, PID 저장 …)은 결함이 있으며 그 안에 구멍이 있습니다. 그냥 말할 아니오 .

대신 프로세스를 부모 프로세스로 모니터하는 프로세스가 필요합니다. 이것은 무엇을 의미 하는가? 프로세스를 시작한 프로세스 만 프로세스가 끝날 때까지 안정적으로 기다릴 수 있음을 의미합니다. bash에서 이것은 절대적으로 사소합니다.

until myserver; do
    echo "Server 'myserver' crashed with exit code $?.  Respawning.." >&2
    sleep 1
done

위의 bash 코드는 루프 myserver에서 실행됩니다 until. 첫 번째 줄이 시작 myserver되고 끝날 때까지 기다립니다. 종료되면 until종료 상태를 확인합니다. 종료 상태가 0인 경우 정상적으로 종료되었음을 의미합니다 (어쨌든 종료하도록 요청했으며 성공적으로 종료되었음을 의미 함). 이 경우 다시 시작하고 싶지 않습니다 (방금 시스템 종료를 요청했습니다!). 종료 상태 인 경우 하지 0 , untilSTDERR에 에러 메시지를 방출 루프 (라인 1 등을) 다시 시작 루프 본문, 실행 1 초 후에을 .

왜 우리는 잠시 기다려? 시작 시퀀스에 문제가 있고 myserver즉시 충돌하는 경우, 일정하게 다시 시작하고 손에 충돌하는 매우 집중적 인 루프를 갖게됩니다. 은 sleep 1그에서 긴장을 멀리합니다.

이제이 bash 스크립트 (비동기 적으로)를 시작하기 만하면 myserver필요에 따라이를 모니터링 하고 다시 시작할 수 있습니다. 부팅시 모니터를 시작하려면 (서버를 “생존”으로 재부팅) @reboot규칙을 사용하여 사용자의 cron (1)에서 모니터를 예약 할 수 있습니다 . 다음과 crontab같이 크론 규칙을 엽니 다 .

crontab -e

그런 다음 규칙을 추가하여 모니터 스크립트를 시작하십시오.

@reboot /usr/local/bin/myservermonitor

대안 적으로; inittab (5) 및 / etc / inittab을보십시오. myserver특정 init 레벨에서 시작하고 자동으로 다시 생성되도록 라인을 추가 할 수 있습니다 .


편집하다.

PID 파일을 사용 하지 않는 이유에 대한 정보를 추가하겠습니다 . 그들은 매우 인기가 있지만; 그들은 또한 매우 결함이 있으며 올바른 방법으로하지 않는 이유가 없습니다.

이걸 고려하세요:

  1. PID 재활용 (잘못된 프로세스 종료) :

    • /etc/init.d/foo start: 시작 foo, fooPID 쓰기/var/run/foo.pid
    • 얼마 후 : foo어떻게 든 죽는다.
    • 잠시 후 : 임의의 프로세스가 시작 (호출 bar)하면 임의 foo의 PID를 사용합니다. 예전 PID를 사용 한다고 상상해보십시오 .
    • 당신은 foo사라졌습니다 : /etc/init.d/foo/restart읽고 /var/run/foo.pid, 아직 살아 있는지 확인하고, 찾고 bar, 생각하고 foo, 죽이고, 새로운 것을 시작합니다 foo.
  2. PID 파일이 오래되었습니다. PID 파일이 오래된 지 여부를 확인하려면 지나치게 복잡하거나 (사소한 말이 아닌) 논리가 필요하며 이러한 논리는 다시 취약합니다 1..

  3. 쓰기 권한이 없거나 읽기 전용 환경에 있다면 어떻게해야합니까?

  4. 무의미한 복잡한 문제입니다. 위의 예제가 얼마나 간단한 지보십시오. 전혀 복잡 할 필요가 없습니다.

참조 : 여전히 결함이 PID-파일을 그것을 ‘권리’를 할 때?

그건 그렇고; PID 파일보다 더 나쁜 것은 파싱입니다 ps! 절대 이러지 마

  1. ps매우 이식이 불가능합니다. 거의 모든 UNIX 시스템에서 찾을 수 있습니다. 비표준 출력을 원하면 인수가 크게 다릅니다. 그리고 표준 출력은 스크립팅 된 구문 분석이 아니라 사람이 소비 할 수 있습니다!
  2. 파싱 ps은 많은 오탐으로 이어집니다. 테이크 ps aux | grep PID예를 들어, 지금 당신이 당신의 데몬을 보았다는 PID와 같은 될 일 인수로 숫자 어딘가로 프로세스를 시작하는 사람을 상상! 두 사람이 X 세션을 시작하고 X가 당신을 죽이려고한다고 상상해보십시오. 그것은 모든 종류의 나쁜 일입니다.

프로세스를 직접 관리하고 싶지 않은 경우 프로세스를 모니터하는 완벽한 시스템이 있습니다. 예를 들어 runit을 살펴보십시오 .


답변

monit ( http://mmonit.com/monit/ )를 살펴보십시오 . 스크립트의 시작, 중지 및 다시 시작을 처리하며 필요한 경우 상태 확인 및 다시 시작을 수행 할 수 있습니다.

또는 간단한 스크립트를 수행하십시오.

while true
do
/your/script
sleep 1
done


답변

가장 쉬운 방법은 파일에서 무리를 사용하는 것입니다. 파이썬 스크립트에서는

lf = open('/tmp/script.lock','w')
if(fcntl.flock(lf, fcntl.LOCK_EX|fcntl.LOCK_NB) != 0):
   sys.exit('other instance already running')
lf.write('%d\n'%os.getpid())
lf.flush()

쉘에서 실제로 실행 중인지 테스트 할 수 있습니다.

if [ `flock -xn /tmp/script.lock -c 'echo 1'` ]; then
   echo 'it's not running'
   restart.
else
   echo -n 'it's already running with PID '
   cat /tmp/script.lock
fi

그러나 물론 테스트 할 필요가 없습니다. 이미 실행 중이고 다시 시작하면 'other instance already running'

프로세스가 종료되면 모든 파일 설명자가 닫히고 모든 잠금이 자동으로 제거됩니다.


답변

시스템에서 여러 가지 사항을 모니터링하고 그에 따라 대응할 수있는 표준 유닉스 도구 인 monit을 사용해야합니다.

문서에서 : http://mmonit.com/monit/documentation/monit.html#pid_testing

pidfile /var/run/checkqueue.pid로 checkqueue.py 프로세스 확인
       pid로 변경되면 "checkqueue_restart.sh"를 실행하십시오.

다시 시작할 때 이메일을 보내도록 monit을 구성 할 수도 있습니다.


답변

if ! test -f $PIDFILE || ! psgrep `cat $PIDFILE`; then
    restart_process
    # Write PIDFILE
    echo $! >$PIDFILE
fi


답변

운영 체제에서 얼마나 이식성이 좋은지 잘 모르겠지만 시스템에 ‘run-one’명령 (예 : “man run-one”)이 있는지 확인할 수 있습니다. 특히,이 명령 세트에는 ‘일관되게 실행’이 포함되며, 이는 정확히 필요한 것 같습니다.

매뉴얼 페이지에서 :

한 번에 COMMAND [ARGS]

참고 : 분명히 스크립트 내에서 호출 할 수는 있지만 스크립트를 가질 필요가 없습니다.


답변

수많은 서버에서 다음 스크립트를 성공적으로 사용했습니다.

pid=`jps -v | grep $INSTALLATION | awk '{print $1}'`
echo $INSTALLATION found at PID $pid
while [ -e /proc/$pid ]; do sleep 0.1; done

노트:

  • Java 프로세스를 찾고 있으므로 jps를 사용할 수 있습니다 .ps보다 배포판에서 훨씬 일관됩니다.
  • $INSTALLATION 완전히 분명한 프로세스 경로를 포함합니다.
  • 프로세스가 죽기를 기다리는 동안 수면을 사용하십시오.

이 스크립트는 실제로 실행중인 Tomcat 인스턴스를 종료하는 데 사용되며 명령 줄에서 종료하고 대기하고 싶습니다. 따라서 자식 프로세스로 시작하는 것은 단순히 옵션이 아닙니다.