smart_open
smart_open copied to clipboard
Automatically reactivate (reconnect) inactive SFTP clients
Problem description
smart_open currently caches SSH clients, (see _SSH and usages in same file).
After opening a connection (_connect()), after it's been unused for some time, the client will time out, e.g.:
`SSHException: SSH session not active`
~/REDACTED/.venv/lib/python3.7/site-packages/smart_open/ssh.py in open(path, mode, host, user, password, port, transport_params)
144
145 conn = _connect(host, user, port, password, transport_params)
--> 146 sftp_client = conn.get_transport().open_sftp_client()
147 fobj = sftp_client.open(path, mode)
148 fobj.name = path
~/REDACTED/.venv/lib/python3.7/site-packages/paramiko/transport.py in open_sftp_client(self)
1095 this transport
1096 """
-> 1097 return SFTPClient.from_transport(self)
1098
1099 def send_ignore(self, byte_count=None):
~/REDACTED/.venv/lib/python3.7/site-packages/paramiko/sftp_client.py in from_transport(cls, t, window_size, max_packet_size)
163 """
164 chan = t.open_session(
--> 165 window_size=window_size, max_packet_size=max_packet_size
166 )
167 if chan is None:
~/REDACTED/.venv/lib/python3.7/site-packages/paramiko/transport.py in open_session(self, window_size, max_packet_size, timeout)
877 window_size=window_size,
878 max_packet_size=max_packet_size,
--> 879 timeout=timeout,
880 )
881
~/REDACTED/.venv/lib/python3.7/site-packages/paramiko/transport.py in open_channel(self, kind, dest_addr, src_addr, window_size, max_packet_size, timeout)
967 """
968 if not self.active:
--> 969 raise SSHException("SSH session not active")
970 timeout = 3600 if timeout is None else timeout
971 self.lock.acquire()
SSHException: SSH session not active
It seems to me this exception can be caught when open_sftp_client() in order to automatically reattempt a reconnect.
Should be straightforward to catch this specific exception and attempt a reconnect, e.g. something like:
def connect_and_open():
conn = _connect(host, user, port, password, transport_params)
return conn.get_transport().open_sftp_client()
try:
sftp_client = connect_and_open()
except: SSHException ex:
if 'SSH session not active' not in ex.message:
raise
_SSH.pop((host, user), None) # invalidate cache
sftp_client = connect_and_open() # try to reconnect, once (and re-cache)
(though in practice, would probably want to some light refactoring to manage the cache cohesively, rather than in multiple places)
Steps/code to reproduce the problem
open() an SFTP endpoint, wait until the client times out, then try to open() it again, such that the same client is returned from the _SSH cache (keyed by hostname and user).
Versions
Darwin-20.6.0-x86_64-i386-64bit
Python 3.7.6 (default, Nov 24 2021, 00:59:23)
[Clang 13.0.0 (clang-1300.0.29.3)]
smart_open 5.2.1
Checklist
Before you create the issue, please make sure you have:
- [X] Described the problem clearly
- [X] Provided a minimal reproducible example, including any required data
- [X] Provided the version numbers of the relevant software
If you're open to accepting a PR, I'd be willing to create a PR based on the example above.
Yes, thank you, please go ahead.