シェルスクリプトのロックは正しいですか?

シェルスクリプトのロックは正しいですか?

時には、シェルスクリプトのインスタンスが一度に1つだけ実行されることを確認する必要があります。

たとえば、crondを介して実行されるcronジョブは、デフォルトでロック(デフォルトのSolaris crondなど)を提供しません。

ロックを実装する一般的なパターンは次のコードです。

#!/bin/sh
LOCK=/var/tmp/mylock
if [ -f $LOCK ]; then            # 'test' -> race begin
  echo Job is already running\!
  exit 6
fi
touch $LOCK                      # 'set'  -> race end
# do some work
rm $LOCK

もちろん、これらのコードには競争条件があります。 1つのインスタンスがファイルにアクセスできる前に、2つのインスタンスの実行が3行目以降に進むことができる時間枠があります$LOCK

クローン操作の場合、呼び出しの間に数分の間隔があるため、これは通常問題ではありません。

ただし、ロックファイルがNFSサーバー上にある場合など、状況が誤って中断される可能性があります。この場合、複数のクローン操作がブロックされ、ライン3に待機できます。 NFSサーバーが再度有効になった場合素晴らしい群れジョブは並列に実行されます。

オンライン検索でこのツールを見つけました。ロックされた操作これはこの問題に対する良い解決策のようです。これにより、次のようにロックが必要なスクリプトを実行できます。

$ lockrun --lockfile=/var/tmp/mylock myscript.sh

ラッパーに入れるか、crontabで使用できます。

利用可能な場合は(POSIX)を使用し、(BSD)lockf()に置き換えられます。flock()そして、lockf()NFSのサポートは比較的広範囲でなければなりません。

どんな選択肢がありますかlockrun

他のcronデーモンはどうですか?合理的な方法でロックを実行するための一般的なクローンサポートはありますか? Vixie Crond(Debian / Ubuntuシステムのデフォルト)のマニュアルページを少し見てみると、ロックに関する情報はまったく表示されません。

lockrun同様のツールを含めるのは良い考えですか?コアツール

私が見るには、それが実装するテーマが次のように非常に似ているようです。timeoutniceそして友達。

ベストアンサー1

これは、両方の操作がライン3を通過できる上記の競合状態を防ぐシェルスクリプトをロックする別の方法です。このnoclobberオプションはkshとbashで動作します。set noclobbercsh / tcshにスクリプトを作成しないでください。使用しないでください。 ;)

lockfile=/var/tmp/mylock

if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then

        trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT

        # do stuff here

        # clean up after yourself, and release your trap
        rm -f "$lockfile"
        trap - INT TERM EXIT
else
        echo "Lock Exists: $lockfile owned by $(cat $lockfile)"
fi

YMMVはNFSをロックしますが(NFSサーバーにアクセスできない場合)、全体的に以前より強力になりました。 (10年前)

同時に同じタスクを実行する複数のサーバーのクローンタスクがありますが、実際に実行するにはインスタンスが1つだけ必要な場合は、同様のタスクが適している可能性があります。

私はlockrunの経験はありませんが、スクリプトが実際に実行される前にロック環境を事前に設定することが役に立ちます。またはそうでないかもしれません。ラッパーのスクリプトの外側でロックされたファイルのテストを設定できますが、理論的には両方の操作でlockrunがまったく同時に呼び出されると、スクリプトの「内部」と同じ競合状態が発生しますか? ?解決策?

それにもかかわらず、ファイルロックはシステムの動作をほとんど尊重し、実行前にロックされたファイルが存在することを確認しないスクリプトは、実行したいすべてのタスクを実行します。ロックファイルのテストと正しい動作だけで、潜在的な問題の99%(100%ではなく)を解決できます。

ロックファイルの競合状態が頻繁に発生する場合は、ジョブのタイミングが正しくないなど、より大きな問題があることを示している可能性があり、間隔がジョブの完了ほど重要ではない場合、ジョブはデーモンに適している可能性があります。


次のように編集 - 2016-05-06(KSH88を使用している場合)


以下の@Clint Pachlのコメントに従ってksh88を使用している場合は、mkdir代わりに使用してくださいnoclobber。これは潜在的な競争条件を主に緩和しますが、完全に制限されません(リスクは少ない)。もっと情報が欲しいなら読んでください以下のClintが投稿したリンク

lockdir=/var/tmp/mylock
pidfile=/var/tmp/mylock/pid

if ( mkdir ${lockdir} ) 2> /dev/null; then
        echo $$ > $pidfile
        trap 'rm -rf "$lockdir"; exit $?' INT TERM EXIT
        # do stuff here

        # clean up after yourself, and release your trap
        rm -rf "$lockdir"
        trap - INT TERM EXIT
else
        echo "Lock Exists: $lockdir owned by $(cat $pidfile)"
fi

さらに、追加のボーナスでスクリプトからtmpファイルを生成する必要がある場合は、スクリプトが終了するlockdirとそのファイルが消去されることを知ってそのディレクトリを使用できます。

より近代的なbashのためには、上部のnoclobber方法が適しています。

おすすめ記事