ruby
59 lines · 8 steps
Building a thread-safe connection pool in Ruby
A bounded pool that reuses connections, lazily creates them up to a cap, and blocks callers until one frees up or a deadline passes.
Explained by
highlit
1require "thread"
2
3class ConnectionPool
4 class TimeoutError < StandardError; end
5
6 def initialize(size: 5, timeout: 5, &factory)
7 raise ArgumentError, "block required to build connections" unless factory
8
9 @factory = factory
10 @timeout = timeout
11 @mutex = Mutex.new
12 @resource = ConditionVariable.new
13 @available = Queue.new
14 @created = 0
15 @max = size
16 end
17
18 def with
19 conn = checkout
20 begin
21 yield conn
22 ensure
23 checkin(conn)
24 end
25 end
26
27 def checkout
28 deadline = clock + @timeout
29
30 @mutex.synchronize do
31 loop do
32 return @available.pop(true) unless @available.empty?
33
34 if @created < @max
35 @created += 1
36 return @factory.call
37 end
38
39 remaining = deadline - clock
40 raise TimeoutError, "waited #{@timeout}s for a connection" if remaining <= 0
41
42 @resource.wait(@mutex, remaining)
43 end
44 end
45 end
46
47 def checkin(conn)
48 @mutex.synchronize do
49 @available.push(conn)
50 @resource.signal
51 end
52 end
53
54 private
55
56 def clock
57 Process.clock_gettime(Process::CLOCK_MONOTONIC)
58 end
59end
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A condition variable lets waiting threads sleep until a resource is returned, avoiding busy-loops while holding a lock.
- 2Lazily creating resources up to a cap balances startup cost against a hard limit on concurrent connections.
- 3Wrapping checkout and checkin in an ensure block guarantees resources return to the pool even when the caller raises.
Related explainers
ruby
require "securerandom" require "time" class ICalEvent
Building an iCalendar file in Ruby
serialization
string-formatting
file-formats
Intermediate
10 steps
go
package dedup import ( "hash/fnv"
A rolling Bloom filter deduper in Go
bloom-filter
deduplication
concurrency
Advanced
7 steps
java
@Service @RequiredArgsConstructor public class ExchangeRateService {
Request-scoped rate caching in Spring
request-scope
caching
memoization
Advanced
6 steps
ruby
class Admin::AccountsController < Admin::BaseController before_action :set_account, only: :destroy def destroy
A guarded destroy action in Rails
controllers
callbacks
transactions
Intermediate
8 steps
go
package server import ( "net/http"
Rate limiting HTTP handlers with a token bucket
rate-limiting
token-bucket
middleware
Advanced
7 steps
java
public final class CircuitBreaker { private enum State { CLOSED, OPEN, HALF_OPEN }
How a circuit breaker guards failing calls
state-machine
resilience
concurrency
Advanced
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/building-a-thread-safe-connection-pool-in-ruby-explained-ruby-ba45/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.