着信ファイルに反応する方法

着信ファイルに反応する方法

ディレクトリに追加されたファイルを処理したら、削除する必要があります。ファイルはサイズが大きく(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機能を使用できるようになります。

関連情報