プログラムの多重実行防止
プログラムの多重実行を避ける代表的な方法
自分と同じコマンド名が起動中か確認
/usr/sbin/pidof を使う方法がある
Pythonの文脈だと同一プロセス上での排他制御として登場する
Pythonの multiprocessing.Lock を使う
lockオブジェクトをプロセス間で共有していれば使える
バッチのように、実行プロセス同士でlockオブジェクトを共有していない場合は使えない
/var/run/sales.lock のようなファイルをプログラム起動時に作成
もし次のプログラム起動時に /var/run/sales.lock がもうあれば、自プログラムを終了(多重起動防止)
/var/run/sales.lock を作成したプログラムは、終了時にこのファイルを削除
コードの見た目も仕組みも分かりやすい方法
プログラムが異常終了したとき、 /var/run/sales.lock が取り残されて次の起動ができなくなる可能性がある
起動時にソケットを開く(例: localhost:9999 )
多重起動したプログラムが同じソケットを開こうとして、 Address already in use エラーになることで、多重起動を防止する
プログラムがクラッシュしたら、ソケットは一定時間後に解放される、ファイルは無いのでゴミは残らない
たまたま9999ポートを利用するプログラムがあると競合してしまうため、環境にあわせてどのポートを使うか変更が必要
起動時にソケットを開く(例: /var/run/sales.sock )
期待する動作は、ソケット利用と同じ。ただし、こちらの方法だとファイルの存在が見える
ファイルパスは自由に決めて良いので、「たまたま別のプログラムと競合」はほぼない
プログラムがクラッシュしたら、ソケットは一定時間後に解放される、UNIXドメインソケットファイルはソケット解放で消滅する
ファイルパスへの書き込み権限が必要
起動時にソケットを開く(例: \0sales.sock )
期待する動作は、ソケット利用と同じ。ファイルは存在しない
名前は自由に決めて良いので競合しない
ファイルが存在しないので書き込み権限も不要
プログラムがクラッシュしたら、ソケットは一定時間後に解放される
この「抽象名前空間」はLinuxでしか使えない
mysqlのget_lock関数
実案件で何度かやって安定しているのはMySQLのget_lockなんですよね。プロセスが死んでDBコネクションが切れたらロックが外れる
code:sql
mysql> SELECT GET_LOCK('lock1',10);
GET_LOCK() を使用すると、アプリケーションロックを実装したり、レコードロックのシミュレーションを行なったりできます。名前はサーバー全体にわたってロックされます。1 つのセッション内で名前がロックされた場合は、GET_LOCK() によって、別のセッションによる同じ名前を持つロックのリクエストがブロックされます。これにより、指定されたロック名について合意したクライアントは、その名前を使用すると共同のアドバイザリロックを実行できます。ただし、共同するクライアントのセットに属さないクライアントも、不注意と故意のどちらででも、名前をロックできることに注意してください。したがって、共同するクライアントがその名前をロックできないようにしてください。この可能性を減らす方法の 1 つは、データベース固有またはアプリケーション固有のロック名を使用することです。たとえば、db_name.str または app_name.str 形式のロック名を使用します。
どの方法も、メリット、デメリットがあります。