Skip to content

Commit

Permalink
[#377] fix iRODSSession connection timeout
Browse files Browse the repository at this point in the history
This had stopped working due to changes in session reinitialization code.
  • Loading branch information
d-w-moore authored and alanking committed May 11, 2023
1 parent ef0d6fe commit b17f1e7
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 1 deletion.
8 changes: 7 additions & 1 deletion irods/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from irods import NATIVE_AUTH_SCHEME, PAM_AUTH_SCHEME
import threading
import weakref
from . import DEFAULT_CONNECTION_TIMEOUT

_sessions = None
_sessions_lock = threading.Lock()
Expand Down Expand Up @@ -131,6 +132,7 @@ def __init__(self, configure = True, auto_cleanup = True, **kwargs):
self._env_file = ''
self._auth_file = ''
self.do_configure = (kwargs if configure else {})
self._cached_connection_timeout = kwargs.pop('connection_timeout', DEFAULT_CONNECTION_TIMEOUT)
self.__configured = None
if configure:
self.__configured = self.configure(**kwargs)
Expand Down Expand Up @@ -232,6 +234,8 @@ def configure(self, **kwargs):
connection_refresh_time = self.get_connection_refresh_time(**kwargs)
logger.debug("In iRODSSession's configure(). connection_refresh_time set to {}".format(connection_refresh_time))
self.pool = Pool(account, application_name=kwargs.pop('application_name',''), connection_refresh_time=connection_refresh_time)
conn_timeout = getattr(self,'_cached_connection_timeout',None)
self.pool.connection_timeout = conn_timeout
return account

def query(self, *args):
Expand Down Expand Up @@ -294,7 +298,9 @@ def connection_timeout(self):

@connection_timeout.setter
def connection_timeout(self, seconds):
self.pool.connection_timeout = seconds
self._cached_connection_timeout = seconds
if seconds is not None:
self.pool.connection_timeout = seconds

@staticmethod
def get_irods_password_file():
Expand Down
52 changes: 52 additions & 0 deletions irods/test/connection_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import absolute_import
import os
import sys
import tempfile
import unittest
from irods.exception import NetworkException
import irods.test.helpers as helpers
Expand Down Expand Up @@ -65,6 +66,57 @@ def test_reply_failure(self):
with self.assertRaises(NetworkException):
conn.reply(0)

def test_that_connection_timeout_works__issue_377(self):
sess = self.sess
h = helpers.home_collection(sess)
logical_path = h + '/issue_377_test.file_timeout_test_on_chksum'
rand = os.urandom(1024)*64
obj = local_file = None
try:
# Create a large file.
size = 1024**2 * 100
with tempfile.NamedTemporaryFile(delete = False) as local_file:
while local_file.tell() < size:
local_file.write(rand)
obj = sess.data_objects.put(local_file.name, logical_path, return_data_object = True)

# Set a very short socket timeout and remove all pre-existing socket connections.
# This forces a new connection to be made for any ensuing connections to the iRODS server.

sess.connection_timeout = timeout = 0.01
sess.cleanup()

# Make sure the newly formed connection pool inherits the timeout value.
self.assertAlmostEqual(sess.pool.connection_timeout, timeout)

# Perform a time-consuming operation in the server (ie. computing the checksum of a
# large data object) during which the socket will time out.
with self.assertRaises(NetworkException):
obj.chksum()
finally:
# Set the connection pool's socket timeout interval back to default, and clean up.
sess.connection_timeout = None
sess.cleanup()
obj.unlink(force = True)
if local_file:
os.unlink(local_file.name)

def assert_timeout_value_propagated_to_socket(self, session, timeout_value):
session.collections.get(helpers.home_collection(session))
conn = next(iter(session.pool.idle))
self.assertEqual(conn.socket.gettimeout(), timeout_value)

def test_connection_timeout_parameter_in_session_init__issue_377(self):
timeout = 1.0
sess = helpers.make_session(connection_timeout = timeout)
self.assert_timeout_value_propagated_to_socket(sess, timeout)

def test_assigning_session_connection_timeout__issue_377(self):
sess = self.sess
for timeout in (999999, None):
sess.connection_timeout = timeout
sess.cleanup()
self.assert_timeout_value_propagated_to_socket(sess, timeout)

if __name__ == '__main__':
# let the tests find the parent irods lib
Expand Down

0 comments on commit b17f1e7

Please sign in to comment.