Add support for specifying the ping interval for pools.
This commit is contained in:
parent
932b413226
commit
5680620f02
@ -213,7 +213,7 @@ Module Interface
|
||||
homogeneous=True, externalauth=False, encoding=None, nencoding=None, \
|
||||
edition=None, timeout=0, wait_timeout=0, max_lifetime_session=0, \
|
||||
session_callback=None, max_sessions_per_shard=0, \
|
||||
soda_metadata_cache=False, stmtcachesize=20)
|
||||
soda_metadata_cache=False, stmtcachesize=20, ping_interval=60)
|
||||
|
||||
Create and return a :ref:`session pool object <sesspool>`. Session pooling
|
||||
(also known as connection pooling) creates a pool of available connections
|
||||
@ -333,19 +333,22 @@ Module Interface
|
||||
The stmtcachesize parameter, if specified, is expected to be an integer
|
||||
which specifies the initial value of :data:`~SessionPool.stmtcachesize`.
|
||||
|
||||
The ping_interval parameter, if specified, is expected to be an integer
|
||||
which specifies the initial value of :data:`~SessionPool.ping_interval`.
|
||||
|
||||
.. note::
|
||||
|
||||
This method is an extension to the DB API definition.
|
||||
|
||||
.. versionchanged:: 8.2
|
||||
|
||||
The parameters `soda_metadata_cache` and `stmtcachesize` were added.
|
||||
For consistency and compliance with the PEP 8 naming style, the
|
||||
parameter `waitTimeout` was renamed to `wait_timeout`, the parameter
|
||||
`maxLifetimeSession` was renamed to `max_lifetime_session`, the
|
||||
parameter `sessionCallback` was renamed to `session_callback` and the
|
||||
parameter `maxSessionsPerShard` was renamed to
|
||||
`max_sessions_per_shard`. The old names will continue to work as
|
||||
The parameters `soda_metadata_cache`, `stmtcachesize` and
|
||||
`ping_interval` were added. For consistency and compliance with the PEP
|
||||
8 naming style, the parameter `waitTimeout` was renamed to
|
||||
`wait_timeout`, the parameter `maxLifetimeSession` was renamed to
|
||||
`max_lifetime_session`, the parameter `sessionCallback` was renamed to
|
||||
`session_callback` and the parameter `maxSessionsPerShard` was renamed
|
||||
to `max_sessions_per_shard`. The old names will continue to work as
|
||||
keyword parameters for a period of time. The `threaded` parameter value
|
||||
is ignored and threading is always enabled.
|
||||
|
||||
|
||||
@ -123,6 +123,23 @@ SessionPool Object
|
||||
the session pool.
|
||||
|
||||
|
||||
.. attribute:: SessionPool.ping_interval
|
||||
|
||||
This read-write integer attribute specifies the pool ping interval in
|
||||
seconds. When a connection is acquired from the pool, a check is first made
|
||||
to see how long it has been since the connection was put into the pool. If
|
||||
this idle time exceeds ``ping_interval``, then a :ref:`round-trip <roundtrips>`
|
||||
ping to the database is performed. If the connection is unusable, it is
|
||||
discarded and a different connection is selected to be returned by
|
||||
:meth:`SessionPool.acquire()`. Setting ``ping_interval`` to a negative
|
||||
value disables pinging. Setting it to 0 forces a ping for every
|
||||
``aquire()`` and is not recommended.
|
||||
|
||||
Prior to cx_Oracle 8.2, the ping interval was fixed at 60 seconds.
|
||||
|
||||
.. versionadded:: 8.2
|
||||
|
||||
|
||||
.. method:: SessionPool.release(connection, tag=None)
|
||||
|
||||
Release the connection back to the pool now, rather than whenever __del__
|
||||
|
||||
@ -26,6 +26,11 @@ Version 8.2 (TBD)
|
||||
:meth:`cx_Oracle.SessionPool()` in order to permit specifying the size of
|
||||
the statement cache during the creation of pools and standalone
|
||||
connections.
|
||||
#) Added parameter `ping_interval` to :meth:`cx_Oracle.SessionPool()` to specify
|
||||
the ping interval when acquiring pooled connections. In addition, the
|
||||
attribute :data:`SessionPool.ping_interval` was added in order to permit
|
||||
making adjustments after the pool has been created. In previous cx_Oracle
|
||||
releases a fixed ping interval of 60 seconds was used.
|
||||
#) Added parameter `bypass_decode` to :meth:`Cursor.var()` in order to allow
|
||||
the `decode` step to be bypassed when converting data from Oracle Database
|
||||
into Python strings
|
||||
|
||||
@ -327,18 +327,19 @@ return a different one. This check will not detect cases such as where the
|
||||
database session has been killed by the DBA, or reached a database resource
|
||||
manager quota limit. To help in those cases, :meth:`~SessionPool.acquire()`
|
||||
will also do a full :ref:`round-trip <roundtrips>` ping to the database when it
|
||||
is about to return a connection that was unused in the pool for 60 seconds. If
|
||||
the ping fails, the connection will be discarded and another one obtained before
|
||||
:meth:`~SessionPool.acquire()` returns to the application. Because this full
|
||||
ping is time based, it won't catch every failure. Also network timeouts and
|
||||
session kills may occur after :meth:`~SessionPool.acquire()` and before
|
||||
:meth:`Cursor.execute()`. To handle these cases, applications need to check
|
||||
for errors after each :meth:`~Cursor.execute()` and make application-specific
|
||||
decisions about retrying work if there was a connection failure. Oracle's
|
||||
:ref:`Application Continuity <highavailability>` can do this automatically in
|
||||
some cases. Note both the lightweight and full ping connection checks can mask
|
||||
performance-impacting configuration issues, for example firewalls killing
|
||||
connections, so monitor the connection rate in `AWR
|
||||
is about to return a connection that was unused in the pool for
|
||||
:data:`SessionPool.ping_interval` seconds. If the ping fails, the connection
|
||||
will be discarded and another one obtained before :meth:`~SessionPool.acquire()`
|
||||
returns to the application. Because this full ping is time based, it won't
|
||||
catch every failure. Also network timeouts and session kills may occur after
|
||||
:meth:`~SessionPool.acquire()` and before :meth:`Cursor.execute()`. To handle
|
||||
these cases, applications need to check for errors after each
|
||||
:meth:`~Cursor.execute()` and make application-specific decisions about retrying
|
||||
work if there was a connection failure. Oracle's :ref:`Application Continuity
|
||||
<highavailability>` can do this automatically in some cases. Note both the
|
||||
lightweight and full ping connection checks can mask performance-impacting
|
||||
configuration issues, for example firewalls killing connections, so monitor the
|
||||
connection rate in `AWR
|
||||
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-56AEF38E-9400-427B-A818-EDEC145F7ACD>`__
|
||||
for an unexpected value. You can explicitly initiate a full ping to check
|
||||
connection liveness with :meth:`Connection.ping()` but overuse will impact
|
||||
|
||||
@ -259,6 +259,7 @@ Some general tips for reducing round-trips are:
|
||||
* Make use of PL/SQL procedures which execute multiple SQL statements instead of executing them individually from cx_Oracle.
|
||||
* Use scalar types instead of Oracle Database object types.
|
||||
* Avoid overuse of :meth:`Connection.ping()`.
|
||||
* Avoid setting :data:`SessionPool.ping_interval` to 0 or a small value.
|
||||
* When using SODA, use pooled connections and enable the :ref:`SODA metadata cache <sodametadatacache>`.
|
||||
|
||||
Finding the Number of Round-Trips
|
||||
|
||||
@ -52,8 +52,9 @@ static int cxoSessionPool_init(cxoSessionPool *pool, PyObject *args,
|
||||
"homogeneous", "externalauth", "encoding", "nencoding", "edition",
|
||||
"timeout", "wait_timeout", "max_lifetime_session",
|
||||
"session_callback", "max_sessions_per_shard",
|
||||
"soda_metadata_cache", "stmtcachesize", "waitTimeout",
|
||||
"maxLifetimeSession", "sessionCallback", "maxSessionsPerShard",
|
||||
"soda_metadata_cache", "stmtcachesize", "ping_interval",
|
||||
"waitTimeout", "maxLifetimeSession", "sessionCallback",
|
||||
"maxSessionsPerShard",
|
||||
NULL };
|
||||
|
||||
// parse arguments and keywords
|
||||
@ -74,7 +75,7 @@ static int cxoSessionPool_init(cxoSessionPool *pool, PyObject *args,
|
||||
if (dpiContext_initPoolCreateParams(cxoDpiContext, &dpiCreateParams) < 0)
|
||||
return cxoError_raiseAndReturnInt();
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs,
|
||||
"|OOOiiiOpbpppssOiiiOipIiiOi", keywordList, &usernameObj,
|
||||
"|OOOiiiOpbpppssOiiiOipIiiiOi", keywordList, &usernameObj,
|
||||
&passwordObj, &dsnObj, &minSessions, &maxSessions,
|
||||
&sessionIncrement, &connectionType, &threaded,
|
||||
&dpiCreateParams.getMode, &events, &dpiCreateParams.homogeneous,
|
||||
@ -83,8 +84,9 @@ static int cxoSessionPool_init(cxoSessionPool *pool, PyObject *args,
|
||||
&dpiCreateParams.waitTimeout, &dpiCreateParams.maxLifetimeSession,
|
||||
&sessionCallbackObj, &maxSessionsPerShard,
|
||||
&dpiCommonParams.sodaMetadataCache, &stmtCacheSize,
|
||||
&waitTimeoutDeprecated, &maxLifetimeSessionDeprecated,
|
||||
&sessionCallbackObjDeprecated, &maxSessionsPerShardDeprecated))
|
||||
&dpiCreateParams.pingInterval, &waitTimeoutDeprecated,
|
||||
&maxLifetimeSessionDeprecated, &sessionCallbackObjDeprecated,
|
||||
&maxSessionsPerShardDeprecated))
|
||||
return -1;
|
||||
if (!PyType_Check(connectionType)) {
|
||||
cxoError_raiseFromString(cxoProgrammingErrorException,
|
||||
@ -463,6 +465,21 @@ static PyObject *cxoSessionPool_getOpenCount(cxoSessionPool *pool, void *unused)
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// cxoSessionPool_getPingInterval()
|
||||
// Return the current value of the ping interval set for the pool.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *cxoSessionPool_getPingInterval(cxoSessionPool *pool,
|
||||
void *unused)
|
||||
{
|
||||
int value;
|
||||
|
||||
if (dpiPool_getPingInterval(pool->handle, &value) < 0)
|
||||
return cxoError_raiseAndReturnNull();
|
||||
return PyLong_FromLong(value);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// cxoSessionPool_getSodaMetadataCache()
|
||||
// Return a boolean indicating if the SODA metadata cache is enabled or not.
|
||||
@ -542,6 +559,29 @@ static int cxoSessionPool_setMaxLifetimeSession(cxoSessionPool *pool,
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// cxoSessionPool_setPingInterval()
|
||||
// Set the value of the OCI attribute.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int cxoSessionPool_setPingInterval(cxoSessionPool *pool,
|
||||
PyObject *value, void *unused)
|
||||
{
|
||||
long cValue;
|
||||
|
||||
if (!PyLong_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be an integer");
|
||||
return -1;
|
||||
}
|
||||
cValue = PyLong_AsLong(value);
|
||||
if (PyErr_Occurred())
|
||||
return -1;
|
||||
if (dpiPool_setPingInterval(pool->handle, (int) cValue) < 0)
|
||||
return cxoError_raiseAndReturnInt();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// cxoSessionPool_setSodaMetadataCache()
|
||||
// Set whether the SODA metadata cache is enabled or not.
|
||||
@ -644,6 +684,8 @@ static PyGetSetDef cxoCalcMembers[] = {
|
||||
(setter) cxoSessionPool_setGetMode, 0, 0 },
|
||||
{ "max_lifetime_session", (getter) cxoSessionPool_getMaxLifetimeSession,
|
||||
(setter) cxoSessionPool_setMaxLifetimeSession, 0, 0 },
|
||||
{ "ping_interval", (getter) cxoSessionPool_getPingInterval,
|
||||
(setter) cxoSessionPool_setPingInterval, 0, 0 },
|
||||
{ "soda_metadata_cache", (getter) cxoSessionPool_getSodaMetadataCache,
|
||||
(setter) cxoSessionPool_setSodaMetadataCache, 0, 0 },
|
||||
{ "stmtcachesize", (getter) cxoSessionPool_getStmtCacheSize,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user