들어오는 파일에 반응하는 방법

들어오는 파일에 반응하는 방법

디렉토리에 추가된 파일을 처리한 후 삭제해야 합니다. 파일은 크기가 크고(20KiB ~ 5GiB) 도착이 느릴 수 있습니다( scp또는 를 통해 ftp). 경로(단위 포함 systemd.path)를 어떻게 모니터링하고 새 파일 쓰기가 완료된 경우에만 반응할 수 있습니까? 내 서비스는 파일의 첫 번째 바이트가 기록될 때 항상 트리거되어 전체 파일이 존재하지 않기 때문에 실패하게 되는 것을 발견했습니다.


1번 시도( DirectoryNotEmpty=)

*.path와 함께 사용합니다 DirectoryNotEmpty=.

이점:

  • 내가 원하는 것 같아

결점:

  • 너무 일찍 트리거되었습니다. 작업하는 동안 파일이 계속 전송되고 있어 불완전(손상)되었습니다.
# /etc/systemd/system/incoming.path

[Path]
DirectoryNotEmpty=/var/incoming

# /etc/systemd/system/incoming.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/incoming

# /usr/local/bin/incoming

for i in /var/incoming/*; do
  process $i
  rm $i
done

시도 2(설문조사)

나는 *.timer매분마다 스크립트를 실행합니다.

이점:

  • 단순한

결점:

  • 작은 파일의 경우 약 90%의 시간 동안 작동하고, 큰 파일의 경우 약 0%의 시간 동안 작동합니다.
  • 파이프라인에 최대 1분 지연 추가
  • 수신 장치 시작/중지로 인해 로그 로그가 복잡해졌습니다.
# /etc/systemd/system/incoming.timer

[Timer]
OnCalendar=minutely

# /etc/systemd/system/incoming.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/incoming

# /usr/local/bin/incoming

for i in /var/incoming/*; do
  process $i
  rm $i
done

3번 시도(폴링과 md5)

계속 폴링을 하고 있지만, *md5메인 컨텐츠를 보낸 후 클라이언트에서만 보내는 작은 파일들만 처리하기도 합니다. 이것들은 모두 1 MTU보다 작으므로 쓰기 프로세스 중에 중단되지 않기를 바랍니다.

이점:

  • 항상 작동하는 것 같습니다(그러나 작동하는지 확실하지 않음).

결점:

  • 파이프라인에 최대 1분 지연 추가
  • 수신 장치 시작/중지로 인해 로그 로그가 복잡해졌습니다.
  • 사용자에게는 더 복잡합니다. 사용자 스크립트를 생성 md5sum한 후 파일을 보내야 합니다.뒤쪽에마스터 파일을 보냅니다.
# /etc/systemd/system/incoming.timer

[Timer]
OnCalendar=minutely

# /etc/systemd/system/incoming.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/incoming

# /usr/local/bin/incoming

for i in /var/incoming/*.md5; do
  file=$(basename $i .md5)
  process $file
  rm $file $file.md5
done

답변1

유일한 질문이기 때문에"1번 해봐"파일이 아직 열려 있는 경우 사용할 스크립트를 수정 lsof하고 sleep처리하기 전에 파일이 닫혔는지 확인할 수 있습니다.

이 같은:

# /usr/local/bin/incoming

for i in /var/incoming/*; do
  while [ "$(lsof $i)" != "" ]; do
    sleep 1
  done
  process $i
  rm $i
done

좀 더 생각해 보면, systemd이미 실행 중인 스크립트가 파일이 닫힐 때까지 기다리는 동안 스크립트를 다시 호출하면 경쟁 조건이 발생할 수 있습니다.

이와 같은 것은 경쟁 조건으로 인해 버그가 발생할 가능성이 적습니다(아직 개선의 여지가 있음).

for i in /var/incoming/*; do
    while [ -e $i ]; do
        if [ "$(lsof $i)" != "" ]
        then
            sleep 1
        else
            process $i
            rm $i
        fi
    done
done

답변2

이를 수행하는 전통적인 방법(예: 메일 서버에서)은 쓰기 프로세스가 들어오는 디렉터리에 기록하고 완료되면 파일을 처리 디렉터리로 이동하는 것입니다. 그러면 처리 서비스는 들어오는 파일이 계속 기록되고 있다는 걱정 없이 도착하는 새 파일에 대해 작업을 수행할 수 있습니다.

업로드 프로세스 중에 이름을 바꿀 수 있어야 하지만 DirectoryNotEmpty사용하려고 했던 기능을 사용할 수 있게 됩니다.

관련 정보