Class: ODBA::ConnectionPool
Constant Summary collapse
- POOL_SIZE =
5- SETUP_RETRIES =
3- CONNECTION_LOST_MESSAGES =
ydbd-pg maps every PG::Error - including connection level failures - onto DBI::ProgrammingError, so for that class the message is the only thing that tells a dead connection apart from a malformed statement. Without this list a restart of the database server leaves every pooled connection permanently broken, because the reconnect below never runs.
/ no\ connection\ to\ the\ server | PQsocket | server\ closed\ the\ connection | connection\ not\ open | terminating\ connection | SSL\ connection\ has\ been\ closed | could\ not\ connect\ to\ server /xi
Instance Attribute Summary collapse
-
#connections ⇒ Object
readonly
attr_reader :connections.
-
#dbi_args ⇒ Object
readonly
attr_reader :connections.
Instance Method Summary collapse
-
#_connect ⇒ Object
:nodoc:.
-
#_disconnect ⇒ Object
:nodoc:.
-
#connect ⇒ Object
:nodoc:.
-
#disconnect ⇒ Object
:nodoc:.
-
#initialize(*dbi_args) ⇒ ConnectionPool
constructor
All connections are delegated to DBI.
-
#method_missing(method, *args, &block) ⇒ Object
:nodoc:.
-
#next_connection ⇒ Object
:nodoc:.
-
#reconnect ⇒ Object
:nodoc:.
-
#retryable?(error) ⇒ Boolean
A statement that failed because the connection is gone is worth retrying on a fresh one.
- #size ⇒ Object (also: #pool_size)
Constructor Details
#initialize(*dbi_args) ⇒ ConnectionPool
All connections are delegated to DBI. The constructor simply records the DBI-arguments and reuses them to setup connections when needed.
30 31 32 33 34 35 36 |
# File 'lib/odba/connection_pool.rb', line 30 def initialize(*dbi_args) @dbi_args = dbi_args @opts = @dbi_args.last.is_a?(Hash) ? @dbi_args.pop : {} @connections = [] @mutex = Mutex.new connect end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args, &block) ⇒ Object
:nodoc:
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/odba/connection_pool.rb', line 50 def method_missing(method, *args, &block) # :nodoc: tries = SETUP_RETRIES begin next_connection { |conn| conn.send(method, *args, &block) } rescue NoMethodError, DBI::Error => e warn e if tries > 0 && retryable?(e) sleep(SETUP_RETRIES - tries) tries -= 1 reconnect retry else raise end end end |
Instance Attribute Details
#connections ⇒ Object (readonly)
attr_reader :connections
27 28 29 |
# File 'lib/odba/connection_pool.rb', line 27 def connections @connections end |
#dbi_args ⇒ Object (readonly)
attr_reader :connections
27 28 29 |
# File 'lib/odba/connection_pool.rb', line 27 def dbi_args @dbi_args end |
Instance Method Details
#_connect ⇒ Object
:nodoc:
85 86 87 88 89 90 91 92 93 |
# File 'lib/odba/connection_pool.rb', line 85 def _connect # :nodoc: POOL_SIZE.times { conn = DBI.connect(*@dbi_args) if encoding = @opts[:client_encoding] conn.execute "SET CLIENT_ENCODING TO '#{encoding}'" end @connections.push(conn) } end |
#_disconnect ⇒ Object
:nodoc:
99 100 101 102 103 104 105 106 107 108 |
# File 'lib/odba/connection_pool.rb', line 99 def _disconnect # :nodoc: while (conn = @connections.shift) begin conn.disconnect rescue DBI::InterfaceError, Exception ## we're not interested, since we are disconnecting anyway nil end end end |
#connect ⇒ Object
:nodoc:
81 82 83 |
# File 'lib/odba/connection_pool.rb', line 81 def connect # :nodoc: @mutex.synchronize { _connect } end |
#disconnect ⇒ Object
:nodoc:
95 96 97 |
# File 'lib/odba/connection_pool.rb', line 95 def disconnect # :nodoc: @mutex.synchronize { _disconnect } end |
#next_connection ⇒ Object
:nodoc:
38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/odba/connection_pool.rb', line 38 def next_connection # :nodoc: conn = nil @mutex.synchronize { conn = @connections.shift } yield(conn) ensure @mutex.synchronize { @connections.push(conn) } end |
#reconnect ⇒ Object
:nodoc:
110 111 112 113 114 115 |
# File 'lib/odba/connection_pool.rb', line 110 def reconnect # :nodoc: @mutex.synchronize { _disconnect _connect } end |
#retryable?(error) ⇒ Boolean
A statement that failed because the connection is gone is worth retrying on a fresh one. A statement that failed on its own merits is not - retrying it would only repeat the same error three times.
72 73 74 75 |
# File 'lib/odba/connection_pool.rb', line 72 def retryable?(error) # :nodoc: !error.is_a?(DBI::ProgrammingError) || CONNECTION_LOST_MESSAGES.match?(error..to_s) end |
#size ⇒ Object Also known as: pool_size
77 78 79 |
# File 'lib/odba/connection_pool.rb', line 77 def size @connections.size end |