Class: Incline::GlobalStatus
- Inherits:
-
Object
- Object
- Incline::GlobalStatus
- Defined in:
- lib/incline/global_status.rb
Overview
An interface to a global status/lock file.
The global status/lock file is a simple two line file. The first line is the global status message. The second line is the global status progress.
The real magic comes when we take advantage of exclusive locks. The process that will be managing the status takes an exclusive lock on the status/lock file. This prevents any other process from taking an exclusive lock. It does not prevent other processes from reading from the file.
So the main process can update the file at any time, until it releases the lock. The other processes can read the file at any time, and test for the lock state to determine if the main process is still busy.
Class Method Summary collapse
-
.current ⇒ Object
Gets the current status from the status/lock file.
-
.lock_for(&block) ⇒ Object
Runs the provided block with a lock on the status/lock file.
-
.locked? ⇒ Boolean
Determines if any process currently holds the lock on the status/lock file.
Instance Method Summary collapse
-
#acquire_lock ⇒ Object
Acquires the lock on the status/lock file.
-
#get_message ⇒ Object
Gets the current status message from the status/lock file.
-
#get_percentage ⇒ Object
Gets the current progress from the status/lock file.
-
#get_status ⇒ Object
Gets the current status from the status/lock file.
-
#have_lock? ⇒ Boolean
Determines if this instance has a lock on the status/lock file.
-
#initialize ⇒ GlobalStatus
constructor
Creates a new GlobalStatus object.
-
#is_locked? ⇒ Boolean
Determines if any process has a lock on the status/lock file.
-
#release_lock ⇒ Object
Releases the lock on the status/lock file if this instance holds the lock.
-
#set_message(value) ⇒ Object
Sets the status message if this instance has a lock on the status/lock file.
-
#set_percentage(value) ⇒ Object
Sets the status progress if this instance has a lock on the status/lock file.
-
#set_status(message, percentage) ⇒ Object
Sets the status message and progress if this instance has a lock on the status/lock file.
-
#status_file_path ⇒ Object
Gets the path to the global status/lock file.
Constructor Details
#initialize ⇒ GlobalStatus
Creates a new GlobalStatus object.
23 24 25 |
# File 'lib/incline/global_status.rb', line 23 def initialize @handle = nil end |
Class Method Details
.current ⇒ Object
Gets the current status from the status/lock file.
See #get_status for a description of the returned hash.
200 201 202 |
# File 'lib/incline/global_status.rb', line 200 def self.current global_instance.get_status end |
.lock_for(&block) ⇒ Object
Runs the provided block with a lock on the status/lock file.
If a lock can be acquired, a GlobalStatus object is yielded to the block. The lock will automatically be released when the block exits.
If a lock cannot be acquire, then false is yielded to the block. The block needs to test for this case to ensure that the appropriate error handling is performed.
214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/incline/global_status.rb', line 214 def self.lock_for(&block) return unless block_given? status = GlobalStatus.new if status.acquire_lock begin yield status ensure status.release_lock end else yield false end end |
.locked? ⇒ Boolean
Determines if any process currently holds the lock on the status/lock file.
Returns true if the file is locked, otherwise returns false.
191 192 193 |
# File 'lib/incline/global_status.rb', line 191 def self.locked? global_instance.is_locked? end |
Instance Method Details
#acquire_lock ⇒ Object
Acquires the lock on the status/lock file.
Returns true on success or if this instance already holds the lock. Returns false if another process holds the lock.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/incline/global_status.rb', line 169 def acquire_lock return true if @handle begin @handle = File.open(status_file_path, File::RDWR | File::CREAT) raise StandardError.new('Already locked') unless @handle.flock(File::LOCK_EX | File::LOCK_NB) @handle.rewind @handle.truncate 0 rescue if @handle @handle.flock(File::LOCK_UN) @handle.close end @handle = nil end !!@handle end |
#get_message ⇒ Object
Gets the current status message from the status/lock file.
53 54 55 |
# File 'lib/incline/global_status.rb', line 53 def get_status[:message] end |
#get_percentage ⇒ Object
Gets the current progress from the status/lock file.
59 60 61 62 |
# File 'lib/incline/global_status.rb', line 59 def get_percentage r = get_status[:percent] r.blank? ? nil : r.to_i end |
#get_status ⇒ Object
Gets the current status from the status/lock file.
Returns a hash with three elements:
- message
-
The current status message.
- percent
-
The current status progress.
- locked
-
The current lock state of the status/lock file. (true for locked, false for unlocked)
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 |
# File 'lib/incline/global_status.rb', line 78 def get_status r = {} if have_lock? @handle.rewind r[:message] = (@handle.eof? ? 'The current process is busy.' : @handle.readline.strip) r[:percent] = (@handle.eof? ? '' : @handle.readline.strip) r[:locked] = true elsif is_locked? if File.exist?(status_file_path) begin File.open(status_file_path, 'r') do |f| r[:message] = (f.eof? ? 'The system is busy.' : f.readline.strip) r[:percent] = (f.eof? ? '' : f.readline.strip) end rescue r[:message] = 'The system appears busy.' r[:percent] = '' end else r[:message] = 'No status file.' r[:percent] = '' end r[:locked] = true else r[:message] = 'The system is no longer busy.' r[:percent] = '-' r[:locked] = false end r end |
#have_lock? ⇒ Boolean
Determines if this instance has a lock on the status/lock file.
35 36 37 |
# File 'lib/incline/global_status.rb', line 35 def have_lock? !!@handle end |
#is_locked? ⇒ Boolean
Determines if any process has a lock on the status/lock file.
41 42 43 44 45 46 47 48 49 |
# File 'lib/incline/global_status.rb', line 41 def is_locked? return true if have_lock? begin return true unless acquire_lock ensure release_lock end false end |
#release_lock ⇒ Object
Releases the lock on the status/lock file if this instance holds the lock.
Returns true.
154 155 156 157 158 159 160 161 |
# File 'lib/incline/global_status.rb', line 154 def release_lock return true unless @handle '' @handle.flock(File::LOCK_UN) @handle.close @handle = nil true end |
#set_message(value) ⇒ Object
Sets the status message if this instance has a lock on the status/lock file.
Returns true after successfully setting the message. Returns false if this instance does not currently hold the lock.
115 116 117 118 119 |
# File 'lib/incline/global_status.rb', line 115 def (value) return false unless have_lock? cur = get_status set_status(value, cur[:percent]) end |
#set_percentage(value) ⇒ Object
Sets the status progress if this instance has a lock on the status/lock file.
Returns true after successfully setting the progress. Returns false if this instance does not currently hold the lock.
127 128 129 130 131 |
# File 'lib/incline/global_status.rb', line 127 def set_percentage(value) return false unless have_lock? cur = get_status set_status(cur[:message], value) end |
#set_status(message, percentage) ⇒ Object
Sets the status message and progress if this instance has a lock on the status/lock file.
Returns true after successfully setting the status. Returns false if this instance does not currently hold the lock.
139 140 141 142 143 144 145 146 147 |
# File 'lib/incline/global_status.rb', line 139 def set_status(, percentage) return false unless have_lock? @handle.rewind @handle.truncate 0 @handle.write(.to_s.strip + "\n") @handle.write(percentage.to_s.strip + "\n") @handle.flush true end |