1

The application I'm working on allows users to add additional connections to other databases through a UI. I'm simply trying to create a validation that ensures that a connection can be made. I created a separate class to test the DB connections:

class StoredProcConnection < ActiveRecord::Base
  def self.abstract_class?
    true # So it gets its own connection
  end
end

I then create the connection:

def connect
  adapter = sql_server? ? 'mssql' : 'mysql2'
  default_port = sql_server? ? '1443' : '3306'
  @connection_pool = StoredProcConnection.establish_connection(
    adapter: adapter,
    username: username, 
    password: password, 
    host: host, 
    database: database_name, 
    port: port || default_port,
    timeout: 300)
  end

def connection_pool
  connect unless @connection_pool
  @connection_pool
end

Then I validate it with this method:

def connection_test
  if connection_pool.connection
    #remove the connection from the StoredProcConnection pool
    connection_pool.remove(connection_pool.connection)
    return true
  else
    return false
  end
rescue Exception => error
  logger.info "unable to create connection with connection.id = #{id} - #{error}"
  return false
end

Unfortunately, when it gets to this line with a bad host address like 127.0.0.abcdefg or 666.666.666.666

if connection_pool.connect

The app gets stuck, no errors raised or anything. It just freezes and I have to shut down the server manually.

I have a workaround but it feels quite sloppy. I am just inserting my own timeout in there, but I feel like Active Record should be throwing some kind of error.

def connection_test
  Timeout::timeout(3) {
    if connection_pool.connection
      #remove the connection from the StoredProcConnection pool
      connection_pool.remove(connection_pool.connection)
      return true
    else
      return false
    end
  }
rescue Exception => error
  logger.info "unable to create connection with connection.id = #{id} - #{error}"
  return false
end

Does anyone see anything that might be causing the freeze? It seems pretty straight forward to me. I'm not sure why the connection pool is even created in the first place with a bad host passed in.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Matt Ramirez
  • 673
  • 6
  • 19
  • You are rescuing all `Exceptions` generally considered a bad idea but if you want to that is fine I would just recommend logging the error and then re raising the exception; – engineersmnky Jun 30 '15 at 15:19
  • Thanks engineersmknky, am aware that its considered bad practice, kind of a lazy placeholder atm :) – Matt Ramirez Jun 30 '15 at 19:14

1 Answers1

0

It just freezes...

Odds are good it's not frozen, it's just waiting to see if that connection can be made. TCP/IP has a long timeout value, which fools people into thinking things are frozen, when actually it's being patient.

Few people really understand how the internet works, and how it's really a house built of straw that we try to keep running no matter what. Long IP timeouts are one of the ways that we try to make it self-healing. Software doesn't care about how long something takes, only people care.

Since it appears you're concerned about malformed IP addresses, why aren't you pre-testing them to make sure they're at least in a valid format?

Use Ruby's built-in IPAddr class and try to parse them:

require 'ipaddr'

%w[
  127.0.0.abcdefg 
  666.666.666.666 
  127.0.0.1 
  192.168.0.1
  255.255.255.255
].each do |ip|
  begin
    IPAddr.new ip
    puts "Good: #{ ip }"
  rescue IPAddr::InvalidAddressError => e
    puts "#{ e }: #{ ip }"
  end
end
# >> invalid address: 127.0.0.abcdefg
# >> invalid address: 666.666.666.666
# >> Good: 127.0.0.1
# >> Good: 192.168.0.1
# >> Good: 255.255.255.255

For "fun reading" there's "TCP Timeout and Retransmission" and "TCP Socket no connection timeout".

Community
  • 1
  • 1
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
  • I let it run for a good 60 seconds before I killed the server, that seems like a pretty large timeout value, but perhaps you are correct. Also, thanks for the IP validation concept, I had considered that, though it does not appear to be a factor in this issue, both good and bad IP's don't appear to throw an exception at all (even after waiting for 60 seconds), though I can connect if all the credentials are correct. – Matt Ramirez Jun 30 '15 at 19:21
  • UPDATE: wow... It was a timeout issue, 60 second timeout (I must have been waiting closer to 59 seconds lol) Damn my impatience! – Matt Ramirez Jun 30 '15 at 19:26