Hanging After a Long Period of Inactivity
When a database connection hangs after a long period of inactivity, this document may help you.
When a firewall or a NAT proxy resides between Oracle database server and client, it sometimes drops inactive connections as dead ones. If a client connects to an Oracle server and tries to use the connection after a long sleep (> 1 hour), the client may hang in an effort to use the dropped connection. This issue will be solved by setting TCP keepalive packets whose keepalive time parameter is smaller than the inactive connection timeout.
TCP keepalive is enabled by (ENABLE=broken) in a connect
descriptor. If you use easy connect naming such as //hostname/service_name
,
ruby-oci8 sets the parameter on behalf of you when the tcp_keepalive
property is set. (This is available since ruby-oci8 2.2.4.)
OCI8.properties[:tcp_keepalive] = true
conn = OCI8.new(username, password, '//hostname/service_name')
This is equivalent to the following:
connect_descriptor = "(DESCRIPTION=(ENABLE=broken)(ADDRESS=(PROTOCOL=tcp)(HOST=hostname)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=service_name)))"
conn = OCI8.new(username, password, connect_descriptor)
The default TCP keepalive time is two hours, which may be larger
than the inactive connection timeout. The default
value in the system is configurable via procfs and sysctl on Linux
or registry parameters on Windows. If you have no privilege to
customize the system, you can change per-connection keepalive time
by the tcp_keepalive_time
property.
OCI8.properties[:tcp_keepalive_time] = 600 # 10 minutes
It is supported on the following platforms since ruby-oci8 2.2.4.
- Linux i386 and x86_64
- macOS x86_64
- Windows x86 and x64
- Solaris x86_64
When it is set on unsupported platforms, you get NotImplementedError
.
This feature is implemented with hackish way. When
tcp_keepalive_time
is set, Oracle client library's
procedure linkage table is modified to intercept setsockopt system
call. When Oracle client library issues the system call which enables
TCP keepalive, ruby-oci8 changes the per-connection TCP keepalive time
immediately.
I hope that Oracle adds a new OCI handle attribute to support this feature natively in the future.