Skip to content

Commit

Permalink
Allow restarting pool
Browse files Browse the repository at this point in the history
The implementation of shutdown from
#27 does not actually
provide for a way for the pool to re-create connections, only render the
pool unusable. This implements such a behavior. A new method is added so
as to not change the existing behavior of `shutdown`.
  • Loading branch information
amarshall committed Jan 28, 2021
1 parent 419bf94 commit d50cb6e
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 2 deletions.
1 change: 1 addition & 0 deletions Changes.md
Expand Up @@ -3,6 +3,7 @@
HEAD
------

- Add `reload` to close all connections, recreating them afterwards [Andrew Marshall, #140]
- Add `then` as a way to use a pool or a bare connection with the
same code path [#138]

Expand Down
16 changes: 16 additions & 0 deletions README.md
Expand Up @@ -95,6 +95,22 @@ Shutting down a connection pool will block until all connections are checked in
**Note that shutting down is completely optional**; Ruby's garbage collector will reclaim
unreferenced pools under normal circumstances.

## Reload

You can reload a ConnectionPool instance in the case it is desired to close all
connections to the pool and, unlike `shutdown`, afterwards recreate connections
so the pool may continue to be used. Reloading may be useful after forking the
process.

```ruby
cp = ConnectionPool.new { Redis.new }
cp.reload { |conn| conn.quit }
cp.with { |conn| conn.get('some-count') }
```

Like `shutdown`, this will block until all connections are checked in and
closed.

## Current State

There are several methods that return information about a pool.
Expand Down
9 changes: 9 additions & 0 deletions lib/connection_pool.rb
Expand Up @@ -104,6 +104,15 @@ def shutdown(&block)
@available.shutdown(&block)
end

##
# Reloads the ConnectionPool by passing each connection to +block+ and then
# removing it the pool. Subsequent checkouts will create new connections as
# needed.

def reload(&block)
@available.shutdown(reload: true, &block)
end

# Size of this connection pool
attr_reader :size

Expand Down
7 changes: 5 additions & 2 deletions lib/connection_pool/timed_stack.rb
Expand Up @@ -83,16 +83,18 @@ def pop(timeout = 0.5, options = {})
##
# 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+.
# shutdown will raise +ConnectionPool::PoolShuttingDownError+ unless
# +:reload+ is +true+.

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

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

shutdown_connections
@shutdown_block = nil if reload
end
end

Expand Down Expand Up @@ -144,6 +146,7 @@ def shutdown_connections(options = nil)
conn = fetch_connection(options)
@shutdown_block.call(conn)
end
@created = 0
end

##
Expand Down
10 changes: 10 additions & 0 deletions test/test_connection_pool_timed_stack.rb
Expand Up @@ -102,6 +102,16 @@ def test_pop_shutdown
end
end

def test_pop_shutdown_reload
stack = ConnectionPool::TimedStack.new(1) { Object.new }
object = stack.pop
stack.push(object)

stack.shutdown(reload: true) {}

refute_equal object, stack.pop
end

def test_push
stack = ConnectionPool::TimedStack.new(1) { Object.new }

Expand Down

0 comments on commit d50cb6e

Please sign in to comment.