Class: ConnectionPool::TimedStack

Inherits:
Object
  • Object
show all
Defined in:
lib/connection_pool/timed_stack.rb

Overview

The TimedStack manages a pool of homogeneous connections (or any resource you wish to manage). Connections are created lazily up to a given maximum number.

Examples:

ts = TimedStack.new(size: 1) { MyConnection.new }

# fetch a connection
conn = ts.pop

# return a connection
ts.push conn

conn = ts.pop
ts.pop timeout: 5
#=> raises ConnectionPool::TimeoutError after 5 seconds

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(size: 0, &block) ⇒ TimedStack

Creates a new pool with size connections that are created from the given block.



25
26
27
28
29
30
31
32
33
# File 'lib/connection_pool/timed_stack.rb', line 25

def initialize(size: 0, &block)
  @create_block = block
  @created = 0
  @que = []
  @max = size
  @mutex = Thread::Mutex.new
  @resource = Thread::ConditionVariable.new
  @shutdown_block = nil
end

Instance Attribute Details

#maxObject (readonly)

Returns the value of attribute max.



20
21
22
# File 'lib/connection_pool/timed_stack.rb', line 20

def max
  @max
end

Instance Method Details

#decrement_createdObject

Reduce the created count



143
144
145
# File 'lib/connection_pool/timed_stack.rb', line 143

def decrement_created
  @created -= 1 unless @created == 0
end

#empty?Boolean

Returns true if there are no available connections.

Returns:

  • (Boolean)


125
126
127
# File 'lib/connection_pool/timed_stack.rb', line 125

def empty?
  (@created - @que.length) >= @max
end

#idleObject

The number of connections created and available on the stack.



137
138
139
# File 'lib/connection_pool/timed_stack.rb', line 137

def idle
  @que.length
end

#lengthObject

The number of connections available on the stack.



131
132
133
# File 'lib/connection_pool/timed_stack.rb', line 131

def length
  @max - @created + @que.length
end

#pop(timeout: 0.5, exception: ConnectionPool::TimeoutError) ⇒ Object

Retrieves a connection from the stack. If a connection is available it is immediately returned. If no connection is available within the given timeout a ConnectionPool::TimeoutError is raised.

Other options may be used by subclasses that extend TimedStack.

Parameters:

  • options (Hash)

    a customizable set of options



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/connection_pool/timed_stack.rb', line 62

def pop(timeout: 0.5, exception: ConnectionPool::TimeoutError, **)
  deadline = current_time + timeout
  @mutex.synchronize do
    loop do
      raise ConnectionPool::PoolShuttingDownError if @shutdown_block
      if (conn = try_fetch_connection(**))
        return conn
      end

      connection = try_create(**)
      return connection if connection

      to_wait = deadline - current_time
      if to_wait <= 0
        if exception
          raise exception, "Waited #{timeout} sec, #{length}/#{@max} available"
        else
          return nil
        end
      end
      @resource.wait(@mutex, to_wait)
    end
  end
end

#push(obj) ⇒ Object Also known as: <<

Returns obj to the stack. Additional kwargs are ignored in TimedStack but may be used by subclasses that extend TimedStack.



38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/connection_pool/timed_stack.rb', line 38

def push(obj, **)
  @mutex.synchronize do
    if @shutdown_block
      @created -= 1 unless @created == 0
      @shutdown_block.call(obj)
    else
      store_connection obj, **
    end

    @resource.broadcast
  end
end

#reap(idle_seconds:) ⇒ Object

Reaps connections that were checked in more than idle_seconds ago.

Raises:

  • (ArgumentError)


106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/connection_pool/timed_stack.rb', line 106

def reap(idle_seconds:)
  raise ArgumentError, "reap must receive a block" unless block_given?
  raise ArgumentError, "idle_seconds must be a number" unless idle_seconds.is_a?(Numeric)
  raise ConnectionPool::PoolShuttingDownError if @shutdown_block

  count = idle
  count.times do
    conn = @mutex.synchronize do
      raise ConnectionPool::PoolShuttingDownError if @shutdown_block
      reserve_idle_connection(idle_seconds)
    end
    break unless conn

    yield conn
  end
end

#shutdown(reload: false, &block) ⇒ Object

Shuts down the TimedStack by passing each connection to block and then removing it from the pool. Attempting to checkout a connection after shutdown will raise ConnectionPool::PoolShuttingDownError unless :reload is true.

Raises:

  • (ArgumentError)


92
93
94
95
96
97
98
99
100
101
102
# File 'lib/connection_pool/timed_stack.rb', line 92

def shutdown(reload: false, &block)
  raise ArgumentError, "shutdown must receive a block" unless block

  @mutex.synchronize do
    @shutdown_block = block
    @resource.broadcast

    shutdown_connections
    @shutdown_block = nil if reload
  end
end