Class: KnoxCall::CredentialsFile::Lock
- Inherits:
-
Object
- Object
- KnoxCall::CredentialsFile::Lock
- Defined in:
- lib/knoxcall/credentials_file.rb
Overview
Sibling .lock file held by exclusive-create (O_CREAT|O_EXCL).
Protocol (identical in every SDK): retry every 100ms up to 10s; a lock file older than the stale window is broken and retried once.
Ownership-aware break/release: the lock file carries a unique owner tag (+pid time nonce+) written at acquire. A stale lock is broken by ATOMIC RENAME (only one racer wins the rename, so a competitor's freshly-created lock can never be deleted by path), and release only unlinks a lock whose on-disk content still matches what this instance wrote. This closes the double-acquire -> double-refresh race that would replay the single-use refresh token and trip server-side family revocation. The stale window is also kept safely above the bounded refresh HTTP timeout (REFRESH_TIMEOUT_SECONDS) so a live-but-slow refresh is never mistaken for a dead holder.
Constant Summary collapse
- STALE_AFTER_SECONDS =
Must exceed the bounded refresh HTTP timeout (REFRESH_TIMEOUT_SECONDS) so a legitimately in-flight refresh is never broken as "stale".
60.0
Instance Attribute Summary collapse
-
#lock_path ⇒ Object
readonly
Returns the value of attribute lock_path.
Instance Method Summary collapse
- #acquire ⇒ Object
-
#initialize(target, timeout: 10.0, retry_interval: 0.1, stale_after: STALE_AFTER_SECONDS) ⇒ Lock
constructor
A new instance of Lock.
- #release ⇒ Object
- #with_lock ⇒ Object
Constructor Details
#initialize(target, timeout: 10.0, retry_interval: 0.1, stale_after: STALE_AFTER_SECONDS) ⇒ Lock
Returns a new instance of Lock.
215 216 217 218 219 220 221 222 |
# File 'lib/knoxcall/credentials_file.rb', line 215 def initialize(target, timeout: 10.0, retry_interval: 0.1, stale_after: STALE_AFTER_SECONDS) @lock_path = "#{target}.lock" @timeout = timeout @retry_interval = retry_interval @stale_after = stale_after @held = false @own_content = nil end |
Instance Attribute Details
#lock_path ⇒ Object (readonly)
Returns the value of attribute lock_path.
213 214 215 |
# File 'lib/knoxcall/credentials_file.rb', line 213 def lock_path @lock_path end |
Instance Method Details
#acquire ⇒ Object
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/knoxcall/credentials_file.rb', line 224 def acquire deadline = monotonic_now + @timeout stale_broken = false loop do return if try_acquire if !stale_broken && break_stale stale_broken = true return if try_acquire end if monotonic_now >= deadline raise Error, "timed out waiting for the credentials file lock (#{@lock_path})" end sleep @retry_interval end end |
#release ⇒ Object
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/knoxcall/credentials_file.rb', line 240 def release return unless @held @held = false own = @own_content @own_content = nil begin # Only remove the lock if it is still OURS — if our lock was broken as # stale and re-taken by another process while we were suspended, # unlink by path would delete their live lock. if own && File.read(@lock_path) == own File.unlink(@lock_path) end rescue SystemCallError # already gone or unreadable end end |
#with_lock ⇒ Object
257 258 259 260 261 262 263 264 |
# File 'lib/knoxcall/credentials_file.rb', line 257 def with_lock acquire begin yield ensure release end end |