디렉토리에 추가된 파일을 처리한 후 삭제해야 합니다. 파일은 크기가 크고(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
사용하려고 했던 기능을 사용할 수 있게 됩니다.