Skip to content

Instantly share code, notes, and snippets.

@pond
Created May 7, 2014 04:30
Show Gist options
  • Save pond/2942792d222e207d82a7 to your computer and use it in GitHub Desktop.
Save pond/2942792d222e207d82a7 to your computer and use it in GitHub Desktop.
AR patch to poll SELECT 1 is-alive query on PostgreSQL in a manner which can be timed out (in theory)
# Is this connection alive and ready for queries?
def active?
begin
conn = @connection
timeout = 5 # seconds
# Now grab a reference to the underlying socket so we know when the
# connection is established
socket = conn.socket_io # AKA IO.for_fd(conn.socket) - same thing
# Track the progress of the connection, waiting for the socket to become readable/writable
# before polling it
poll_status = PG::PGRES_POLLING_WRITING
until poll_status == PG::PGRES_POLLING_OK || poll_status == PG::PGRES_POLLING_FAILED
# If the socket needs to read, wait 'til it becomes readable to poll again
case poll_status
when PG::PGRES_POLLING_READING
IO.select( [socket], nil, nil, timeout ) or raise "Asynchronous connection timed out!"
# ...and the same for when the socket needs to write
when PG::PGRES_POLLING_WRITING
IO.select( nil, [socket], nil, timeout ) or raise "Asynchronous connection timed out!"
end
# Other states...
# case conn.status
# when PG::CONNECTION_STARTED
# output_progress " waiting for connection to be made."
# when PG::CONNECTION_MADE
# output_progress " connection OK; waiting to send."
# when PG::CONNECTION_AWAITING_RESPONSE
# output_progress " waiting for a response from the server."
# when PG::CONNECTION_AUTH_OK
# output_progress " received authentication; waiting for backend start-up to finish."
# when PG::CONNECTION_SSL_STARTUP
# output_progress " negotiating SSL encryption."
# when PG::CONNECTION_SETENV
# output_progress " negotiating environment-driven parameter settings."
# when PG::CONNECTION_NEEDED
# output_progress " internal state: connect() needed."
# end
# Check to see if it's finished or failed yet
poll_status = conn.connect_poll
end
raise "Connect failed: %s" % [ conn.error_message ] unless conn.status == PG::CONNECTION_OK
# Send check-alive query
conn.send_query( "SELECT 1" )
# Fetch results until there aren't any more
loop do
# Buffer any incoming data on the socket until a full result is ready.
conn.consume_input
while conn.is_busy
IO.select( [socket], nil, nil, timeout ) or raise "Timeout waiting for query response."
conn.consume_input
end
# Fetch the next result. If there isn't one, the query is finished
result = conn.get_result or break
end
true
rescue => e
puts "FAILED, returning 'false': #{e}"
false
end
# begin
# @connection.query 'SELECT 1'
# true
# rescue PGError
# false
# end
end
def active_threadsafe?
active?
# This doesn't actually check activity correctly anyway.
# It was the source of bugs in Rails 4.0.0 and 4.0.1.
#
# https://github.com/rails/rails/issues/12867
#
# @connection.connect_poll != PG::PGRES_POLLING_FAILED
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment