main
 1# frozen_string_literal: true
 2
 3module Net
 4  module Hippie
 5    # Thread-safe connection pool with LRU eviction.
 6    class ConnectionPool
 7      def initialize(max_size: 100, dns_ttl: 300)
 8        @max_size = max_size
 9        @dns_ttl = dns_ttl
10        @connections = {}
11        @monitor = Monitor.new
12      end
13
14      def checkout(key, &block)
15        reuse(key) || create(key, &block)
16      end
17
18      def close_all
19        @monitor.synchronize do
20          @connections.each_value(&:close)
21          @connections.clear
22        end
23      end
24
25      private
26
27      def reuse(key)
28        @monitor.synchronize do
29          return nil unless @connections.key?(key)
30
31          conn = @connections.delete(key)
32          return @connections[key] = conn unless conn.stale?(@dns_ttl)
33
34          conn.close
35          nil
36        end
37      end
38
39      def create(key)
40        conn = yield
41        @monitor.synchronize do
42          existing = reuse(key)
43          if existing
44            conn.close
45            return existing
46          end
47          evict_lru if @connections.size >= @max_size
48          @connections[key] = conn
49        end
50      end
51
52      def evict_lru
53        key, conn = @connections.first
54        conn.close
55        @connections.delete(key)
56      end
57    end
58  end
59end