Created
May 7, 2014 04:30
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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