module PG::Connection::Pollable
def polling_loop(poll_meth)
- When a timeout occurs, connecting is restarted with the remaining hosts.
- When the polling status changes to `PG::PGRES_POLLING_FAILED` connecting is aborted and a PG::ConnectionBad is raised with details to all connection attepts.
- When the polling status changes to `PG::PGRES_POLLING_OK` the connection is returned and ready to use.
- As soon as the host is tried to connect the related host is removed from the hosts list
- All hosts are passed to PG::Connection.connect_start
Connecting to multiple hosts is done like so:
Track the progress of the connection, waiting for the socket to become readable/writable before polling it.
def polling_loop(poll_meth) _timeout = conninfo_hash[:connect_timeout] eo = connect_timeout.to_i) && timeo > 0 ount = (conninfo_hash[:hostaddr].to_s.empty? ? conninfo_hash[:host] : conninfo_hash[:hostaddr]).to_s.count(",") + 1 ime = timeo * host_count + Process.clock_gettime(Process::CLOCK_MONOTONIC) conninfo_hash.compact ion_errors = [] atus = PG::PGRES_POLLING_WRITING oll_status == PG::PGRES_POLLING_OK || status == PG::PGRES_POLLING_FAILED single timeout to parameter "connect_timeout" but t exceed total connection time of number-of-hosts * connect_timeout. t = [timeo, stop_time - Process.clock_gettime(Process::CLOCK_MONOTONIC)].min if stop_time t = remove_current_host(iopts) = if !timeout || timeout >= 0 the socket needs to read, wait 'til it becomes readable to poll again poll_status PG::PGRES_POLLING_READING efined?(IO::READABLE) # ruby-3.0+ ket_io.wait(IO::READABLE | IO::PRIORITY, timeout) select([socket_io], nil, [socket_io], timeout) and the same for when the socket needs to write PG::PGRES_POLLING_WRITING efined?(IO::WRITABLE) # ruby-3.0+ se wait instead of wait_readable, since connection errors are delivered as xceptional/priority events on Windows. ket_io.wait(IO::WRITABLE | IO::PRIORITY, timeout) o#wait on ruby-2.x doesn't wait for priority, so fallback to IO.select select(nil, [socket_io], [socket_io], timeout) ection to server at "localhost" (127.0.0.1), port 5433 failed: timeout expired (PG::ConnectionBad) ection to server on socket "/var/run/postgresql/.s.PGSQL.5433" failed: No such file or directory event ction_errors << (error_message + "timeout expired") stcnt > 0 t_start2(self.class.parse_connect_args(iopts)) start polling with waiting for writable. herwise "not connected" error is raised on Windows. _status = PG::PGRES_POLLING_WRITING sh e PG::ConnectionBad.new(connection_errors.join("\n").b, connection: self) k to see if it's finished or failed yet tatus = send( poll_meth ) status == PG::CONNECTION_OK error_message PG::ConnectionBad.new(connection_errors.map{|e| e + "\n" }.join.b + msg, connection: self)
def remove_current_host(iopts)
- :port
- :hostaddr
- :host
Affected options are:
Remove the host to which the connection is currently established from the option hash.
def remove_current_host(iopts) = iopts[:host]&.split(",", -1) drs = iopts[:hostaddr]&.split(",", -1) = iopts[:port]&.split(",", -1) = iports * (ihosts || ihostaddrs || [1]).size if iports&.size == 1 ihosts || ihostaddrs || iports).index.with_index do |_, i| s ? ihosts[i] == host : true) && addrs && respond_to?(:hostaddr, true) ? ihostaddrs[i] == hostaddr : true) && s ? iports[i].to_i == port : true) &.delete_at(idx) ddrs&.delete_at(idx) &.delete_at(idx) merge!( ihosts.join(",")) if ihosts merge!( ddr: ihostaddrs.join(",")) if ihostaddrs merge!( iports.join(",")) if iports || ihostaddrs || iports).size