Module: CountingSemaphore::WithLeaseSupport

Included in:
LocalSemaphore, RedisSemaphore
Defined in:
lib/counting_semaphore/with_lease_support.rb

Overview

Module providing backwards-compatible with_lease method Requires the including class to implement: acquire, release, capacity

Instance Method Summary collapse

Instance Method Details

#currently_leased ⇒ Integer

Get the current number of permits currently acquired. Kept for backwards compatibility.

Returns:

  • (Integer) —

    Number of permits currently in use



56
57
58
# File 'lib/counting_semaphore/with_lease_support.rb', line 56

def currently_leased
  capacity - available_permits
end

#with_lease(permit_count = 1, timeout: 30) {|lease| ... } ⇒ Object

Acquire a lease for the specified number of permits and execute the block. Blocks until sufficient resources are available. Kept for backwards compatibility - wraps acquire/release.

Parameters:

  • permit_count (Integer) (defaults to: 1) —

    Number of permits to acquire (default: 1)

  • timeout (Numeric) (defaults to: 30) —

    Maximum time in seconds to wait for lease acquisition (default: 30). For Redis-backed semaphores, the timeout value will be rounded up to the nearest whole second due to Redis BLPOP limitations.

Yields:

  • (lease) —

    The block to execute while holding the lease

Yield Parameters:

Returns:

  • The result of the block

Raises:

  • (ArgumentError) —

    if permit_count is negative or exceeds the semaphore capacity

  • (CountingSemaphore::LeaseTimeout) —

    if lease cannot be acquired within timeout



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/counting_semaphore/with_lease_support.rb', line 20

def with_lease(permit_count = 1, timeout: 30)
  permit_count = permit_count.to_i
  raise ArgumentError, "Permit count must be non-negative, got #{permit_count}" if permit_count < 0
  if permit_count > capacity
    raise ArgumentError, "Cannot lease #{permit_count} permits as capacity is only #{capacity}"
  end

  # Handle zero permits case - no waiting needed
  return yield(nil) if permit_count.zero?

  # Use try_acquire with timeout
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  lease = nil

  loop do
    elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
    if elapsed_time >= timeout
      raise CountingSemaphore::LeaseTimeout.new(permit_count, timeout, self)
    end

    remaining_timeout = timeout - elapsed_time
    lease = try_acquire(permit_count, timeout: remaining_timeout)
    break if lease
  end

  begin
    yield(lease)
  ensure
    release(lease) if lease
  end
end