连接不会引发错误主机

Connection won't raise error with bad host

我正在开发的应用程序允许用户通过 UI 添加到其他数据库的额外连接。我只是想创建一个确保可以建立连接的验证。 我创建了一个单独的 class 来测试数据库连接:

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

然后我创建连接:

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

然后我用这个方法验证一下:

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

不幸的是,当它到达带有错误主机地址的这一行时,如 127.0.0.abcdefg666.666.666.666

if connection_pool.connect

应用程序卡住了,没有出现任何错误。它只是冻结,我必须手动关闭服务器。

我有一个解决方法,但感觉很草率。我只是在那里插入我自己的超时,但我觉得 Active Record 应该抛出某种错误。

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

有没有人看到任何可能导致冻结的原因?这对我来说似乎很简单。我不确定为什么在传入错误主机的情况下甚至首先创建连接池。

It just freezes...

很有可能它没有被冻结,它只是在等着看是否可以建立连接。 TCP/IP 有一个很长的超时值,它使人们误以为事情已经冻结,而实际上它是在耐心等待。

很少有人真正了解互联网是如何运作的,以及它是如何真正成为我们无论如何都试图保留 运行 的稻草屋。长 IP 超时是我们尝试使其自我修复的方法之一。软件不关心需要多长时间,只有人在乎。

既然您担心 IP 地址格式不正确,为什么不预先测试它们以确保它们至少采用有效格式?

使用 Ruby 的内置 IPAddr class 并尝试解析它们:

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

"fun reading" 有“TCP Timeout and Retransmission" and "TCP Socket no connection timeout”。