inotifywait를 사용하여 긴급 상황 모니터링

inotifywait를 사용하여 긴급 상황 모니터링

를 통과하는 서비스가 있습니다 rsync. 이런 일이 발생하면 서버 측 프로그램의 실행을 트리거하고 싶습니다.

이 명령 덕분에 inotifywait파일이나 디렉터리의 변경 사항을 모니터링하는 것이 매우 쉽습니다. 하지만 난 알림을 받고 싶어버스트를 한 번만 수정하세요., 업로드 후 프로세스가 무겁고 수정된 모든 파일에 대해 이를 수행하고 싶지 않기 때문입니다.

이벤트 타임스탬프를 기반으로 몇 가지 해킹을 생각해 내는 것은 큰 노력이 아닐 것입니다... 그러나 저는 이것이 상당히 일반적인 문제라고 믿습니다. 그러나 나는 유용한 것을 찾을 수 없었습니다.

갑작스러운 문제를 해결할 수 있는 기발한 명령이 있나요? 나는 다음과 같이 사용할 수 있는 것을 생각하고 있습니다.

inotifywait -m "$dir" $opts | detect_burst --execute "$post_upload"

답변1

자신의 답변에 따라 쉘을 사용하려는 경우 시간 초과 시 반환 코드를 >128로 설정하는 시간 초과 옵션을 read활용할 수 있습니다 . -t예를 들어 burst스크립트는 대략적으로 다음과 같을 수 있습니다.

interval=$1; shift
while :
do  if read -t $interval
    then    echo "$REPLY"            # not timeout
    else    [ $? -lt 128 ] && exit   # eof
            "$@"
            read || exit    # blocking read infinite timeout
            echo "$REPLY"
    fi
done

처음에 버스트의 끝을 감지하지 않으려면 초기 차단 읽기부터 시작하는 것이 좋습니다.

답변2

OP가 여기에 있습니다.

내가 생각해낸 해결책은 다음과 같은 프로그램입니다 burst.

inotifywait -e moved_to "$monitored_dir" -m \
    | burst 2 'echo run post-upload'

스크립트 burst:

#!/bin/bash

help() {
    >&2 echo "Usage: $0 <interval> <command>"
}

set -e
trap help EXIT
interval=${1:?missing interval}; shift
: ${1:?missing command}

trap - EXIT
set +e
exec 3> >(sed "s/^/burst: /" >&2)
while read line; do
    echo "$line" >&3
    test -n "$!" && kill -term $! 2>/dev/null
    (sleep $interval && $SHELL -c "$*") &
done

기본적으로 이는 실제 명령( )을 실행하기 전에 정의된 시간 동안 기다리는 하위 쉘을 생성합니다 (sleep $interval && $SHELL -c "$*"). 새로 읽은 줄은 inotifywait해당 쉘(존재하는 경우)을 종료하고 다시 생성합니다.

일련의 행이 끝나면 쉘이 종료되고 sleep명령이 실행됩니다.

몇 가지 단점이 있습니다:

  1. stdin의 각 줄에 대한 프로세스를 종료하고 생성합니다. 이는 먼저 행 수를 줄이고 싶다는 의미입니다(따라서 -e moved_to필터 inotifywait). 업로드된 파일의 수가 너무 많으면, WRT 성능을 감당할 수 없습니다!

  2. 몇 초 후 $interval(또는 파일 전송에 해당 시간이 소요됨) 두 번째 버스트가 발생하면 실행 중인 업데이트 후 프로세스가 종료될 가능성이 높습니다. 그러한 프로세스가 멱등성이거나 트랜잭션이라면 괜찮습니다... 그러니 주의하세요.

답변3

주인. 가능한 해결책은 다음과 같습니다.

inotifywait -m "$dir" -e moved_to --timefmt='%s' --format '%T' | stdbuf -oL uniq | ...

편집하다: IMHO 두 번째 답변이 더 좋기 때문에 이 질문에 대한 다른 답변을 참조하세요.

move_to단일 파일 전송의 마지막 단계인 각 실행 시 epoch 이후 시간을 인쇄하여 작동합니다 .

업로드가 1초 이상 지속되더라도 업로드 후 프로세스가 여러 번 실행될 수 있지만 이 방법은 제대로 작동합니다.

--timefmt플래그를 다른 값으로 변경하면 다른 세분성을 얻을 수 있습니다.

별로 마음에 들지는 않지만 반쯤 좋은 생각으로 여기에 게시합니다... 그래도 공유하고 싶었습니다.

답변4

현재 시간을 확인하고 이전 이벤트와 동일한(또는 더 일반적으로 정의할 수 있는 방식으로 유사한) 이벤트를 건너뛰는 루프를 만들 수 있습니다. bash, ksh 또는 zsh에서 다음의 간단한 루프는 10초 내에 반복되는 이벤트를 건너뜁니다.

inotifywait -m … | {
  previous_SECONDS=0
  previous_event=
  while IFS= read -r event; do
    if [[ "$event" = "$previous_event" && $SECONDS <= $previous_SECONDS + 10 ]]; then
      continue
    fi
    previous_SECONDS=$SECONDS previous_event=$event
    "$post_upload" "$event"
  done
}

쉘은 고성능 텍스트 처리에 좋지 않기 때문에 다른 도구를 사용하는 것이 좋습니다. 역사적인 이유로 시간(에포크 이후 초)을 노출하는 매우 이상한 방법이 있는 awk를 사용할 수 있습니다. 호출은 srand()마지막 호출을 반환합니다 srand().

inotifywait -m … | awk '
    {srand(); current_time = srand()}
    $0 == previous_event && current_time <= previous_time + 10 {
        system(ENVIRON["post_upload"])
    }
    {previous_event = $0; previous_time = current_time}
'

이식성이 꼭 필요한 것이 아니라면 이식성을 포기하고 Perl, Python 또는 Ruby와 같은 더 높은 수준의 스크립팅 언어를 사용하겠습니다. 이러한 언어에는 모두 inotify 인터페이스가 있으므로 호출 inotifywait하고 텍스트 구문 분석을 수행할 필요가 없습니다 .

관련 정보