Techioz Blog

File#flock を Ruby グローバル ロック (プロセスのミューテックス) として使用する

概要

簡単に調べた結果、一時ファイルがこの問題の解決策として提案されていることがわかりましたが、2 つのプロセス間で同時実行の問題が発生しています。

したがって、解決策は /tmp/global.lock を作成し、それをグローバル ロックとして使用することです。このスレッドで見つけた例です。Rails プロセスのミューテックス

ここまでは理解できますが、この解決策のベストプラクティスを見てみたいと思います。上記の説明は理にかなっていますが、指定されたファイルがロックされているかどうかを確認するにはどうすればよいでしょうか?

fh = File.open("/some/file/path", File::CREAT)

begin
  if locked = check_file_locked?
    sleep(1)
  else
    fh.flock(File::LOCK_EX)
    # do what you need to do
  end
ensure
  fh.flock(File::LOCK_UN)
end

これは私の解決策の理解ですが、前述の check_file_locked?() を実装する方法がわかりません。また、最善の方法がある場合は、ぜひ聞いてください。

解決策

@bjhaidの答えは、Timeout#timeoutの問題を引き起こし、Rubiniusでインタープリタエラーを引き起こす可能性があります。それも不必要に複雑です。

以下は、タイムアウトの代わりに非ブロッキング ロックを使用した、より単純なバージョンです。

def locked? lockfile_name
  f = File.open(lockfile_name, File::CREAT)

  # returns false if already locked, 0 if not
  ret = f.flock(File::LOCK_EX|File::LOCK_NB)

  # unlocks if possible, for cleanup; this is a noop if lock not acquired
  f.flock(File::LOCK_UN) 

  f.close
  !ret # ret == false means we *couldn't* get a lock, i.e. it was locked
end