Pond
Pond is a gem that offers thread-safe object pooling. It can wrap anything
that is costly to instantiate, but is usually used for connections. It is
intentionally very similar to the connection_pool
gem, but is intended to be
more efficient and flexible. It instantiates objects lazily by default, which
is important for things with high overhead like Postgres connections. It can
also be dynamically resized, and does not block on object instantiation.
Also, it was pretty fun to write.
Installation
Add this line to your application's Gemfile:
gem 'pond'
And then execute:
$ bundle
Or install it yourself as:
$ gem install pond
Usage
require 'pond'
require 'redis'
$redis_pond = Pond.new(:maximum_size => 5, :timeout => 0.5) { Redis.new }
$redis_pond.checkout do |redis|
redis.incr 'my_counter'
redis.lpush 'my_list', 'item'
end
$redis = Pond.wrap(:maximum_size => 5, :timeout => 0.5) { Redis.new }
$redis.incr 'my_counter'
$redis.lpush 'my_list', 'item'
$redis.pipelined do
$redis.incr 'my_counter'
$redis.lpush 'my_list', 'item'
end
Options:
- :maximum_size - The maximum number of objects you want the pool to contain.
The default is 10.
- :timeout - When attempting to check out an object but none are available,
how many seconds to wait before raising a
Pond::Timeout
error. The
default is 1. Integers or floats are both accepted. - :collection - How to manage the objects in the pool. The default is :queue,
meaning that pond.checkout will yield the object that hasn't been used in
the longest period of time. This is to prevent connections from becoming
'stale'. The alternative is :stack, so checkout will yield the object that
has most recently been returned to the pool. This would be preferable if
you're using connections that have their own logic for becoming idle in
periods of low activity.
- :eager - Set this to true to fill the pool with instantiated objects (up to
the maximum size) when it is created, similar to how the
connection_pool
gem works. - :detach_if - Set this to a callable object that can determine whether
objects should be returned to the pool or not. See the following example for
more information.
Detaching Objects
Sometimes objects in the pool outlive their usefulness (connections may fail)
and it becomes necessary to remove them. Pond's detach_if option is useful for
this - you can pass it any callable object, and Pond will pass it objects from
the pool that have been checked out before they are checked back in. For
example, when using Pond with PostgreSQL connections:
require 'pond'
require 'pg'
$pg_pond = Pond.new(:detach_if => lambda {|c| c.finished?}) do
PG.connect(:dbname => "pond_test")
end
Now, after a PostgreSQL connection has been used, but before it is returned to
the pool, it will be passed to that lambda to see if it should be detached or
not. If the lambda returns truthy, the connection will be detached (and made
available for garbage collection), and a new one will be instantiated to
replace it as necessary (until the pool returns to its maximum size).
Contributing
I don't plan on adding too many more features to Pond, since I want to keep
its design simple. If there's something you'd like to see it do, open an issue
so we can discuss it before going to the trouble of creating a pull request.