Class: PEROBS::LockFile
- Inherits:
-
Object
- Object
- PEROBS::LockFile
- Defined in:
- lib/perobs/LockFile.rb
Overview
This class implements a file based lock. It can only be taken by one process at a time. It support configurable lock lifetime, maximum retries and pause between retries.
Instance Method Summary collapse
-
#forced_unlock ⇒ Object
Erase the lock file.
-
#initialize(file_name, options = {}) ⇒ LockFile
constructor
Create a new lock for the given file.
-
#is_locked? ⇒ Boolean
Check if the lock has been taken.
-
#lock ⇒ Boolean
Attempt to take the lock.
-
#unlock ⇒ Object
Release the lock again.
Constructor Details
#initialize(file_name, options = {}) ⇒ LockFile
Create a new lock for the given file.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/perobs/LockFile.rb', line 40 def initialize(file_name, = {}) @file_name = file_name # The handle of the lock file @file = nil # The maximum duration after which a lock file is considered a left-over # from a dead or malefunctioning process. @timeout_secs = 60 * 60 # The maximum number of times we try to get the lock. @max_retries = 5 # The time we wait between retries @pause_secs = 1 .each do |name, value| case name when :timeout_secs @timeout_secs = value when :max_retries @max_retries = value when :pause_secs @pause_secs = value else PEROBS.log.fatal "Unknown option #{name}" end end end |
Instance Method Details
#forced_unlock ⇒ Object
Erase the lock file. It’s essentially a forced unlock method.
149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/perobs/LockFile.rb', line 149 def forced_unlock @file = nil if File.exist?(@file_name) begin File.delete(@file_name) PEROBS.log.debug "Lock file #{@file_name} has been deleted." rescue IOError => e PEROBS.log.error "Cannot delete lock file #{@file_name}: " + e. end end end |
#is_locked? ⇒ Boolean
Check if the lock has been taken.
121 122 123 |
# File 'lib/perobs/LockFile.rb', line 121 def is_locked? File.exist?(@file_name) end |
#lock ⇒ Boolean
Attempt to take the lock.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/perobs/LockFile.rb', line 68 def lock retries = @max_retries while retries > 0 begin @file = File.open(@file_name, File::RDWR | File::CREAT, 0644) @file.sync = true if @file.flock(File::LOCK_EX | File::LOCK_NB) # We have taken the lock. Write the PID into the file and leave it # open. @file.write($$) @file.flush @file.fsync @file.truncate(@file.pos) PEROBS.log.debug "Lock file #{@file_name} has been taken for " + "process #{$$}" return true else # We did not manage to take the lock file. if @file.mtime <= Time.now - @timeout_secs pid = @file.read.to_i PEROBS.log.info "Old lock file found for PID #{pid}. " + "Removing lock." if is_running?(pid) send_signal('TERM', pid) # Give the process 3 seconds to terminate gracefully. sleep 3 # Then send a SIGKILL to ensure it's gone. send_signal('KILL', pid) if is_running?(pid) end @file.close File.delete(@file_name) if File.exist?(@file_name) else PEROBS.log.debug "Lock file #{@file_name} is taken. Trying " + "to get it #{retries} more times." end end rescue => e PEROBS.log.error "Cannot take lock file #{@file_name}: #{e.}" return false end retries -= 1 sleep(@pause_secs) end PEROBS.log.info "Failed to get lock file #{@file_name} due to timeout" false end |
#unlock ⇒ Object
Release the lock again.
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/perobs/LockFile.rb', line 126 def unlock unless @file PEROBS.log.error "There is no current lock to release" return false end begin @file.flock(File::LOCK_UN) @file.fsync @file.close forced_unlock PEROBS.log.debug "Lock file #{@file_name} for PID #{$$} has been " + "released" rescue => e PEROBS.log.error "Releasing of lock file #{@file_name} failed: " + e. return false end true end |