byteskeptical / sftpretty

Provides multi-threaded routines and high level protocol abstractions for a pretty quick & simple file transfer experience. Super duper close to a drop in replacement for pysftp.
https://docs.sftpretty.com/
BSD 3-Clause "New" or "Revised" License
33 stars 8 forks source link

ChannelException while using get_r #30

Closed coreyhartley closed 1 year ago

coreyhartley commented 1 year ago

We had been using version 1.0.6 for a few weeks in our repo, as well as what is in root for the last few days, and started to notice this exception consistently happening when attempting to use get_r. Most files we tried to get came through, but we would not be able to grab the last few every time. Here is the traceback:

Traceback (most recent call last):
  File "C:\Program Files\Python38\lib\multiprocessing\pool.py", line 125, in worker
    result = (True, func(*args, **kwds))
  File "C:\Users\git\src\interfaces\sbc_interface.py", line 902, in _download_directory
    sftp.get_r(".", local_directory)
  File "C:\Users\git\.venv\lib\site-packages\sftpretty\__init__.py", line 497, in get_r
    self.get_d(
  File "C:\Users\git\.venv\lib\site-packages\sftpretty\__init__.py", line 448, in get_d
    raise err
  File "C:\Users\git\.venv\lib\site-packages\sftpretty\__init__.py", line 445, in get_d
    data = future.result()
  File "C:\Program Files\Python38\lib\concurrent\futures\_base.py", line 432, in result
    return self.__get_result()
  File "C:\Program Files\Python38\lib\concurrent\futures\_base.py", line 388, in __get_result
    raise self._exception
  File "C:\Program Files\Python38\lib\concurrent\futures\thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "C:\Users\git\.venv\lib\site-packages\sftpretty\__init__.py", line 366, in get
    _get(self, remotefile, localpath=localpath, callback=callback,
  File "C:\Users\git\.venv\lib\site-packages\sftpretty\__init__.py", line 355, in _get
    with self._sftp_channel() as channel:
  File "C:\Program Files\Python38\lib\contextlib.py", line 113, in __enter__
    return next(self.gen)
  File "C:\Users\git\.venv\lib\site-packages\sftpretty\__init__.py", line 244, in _sftp_channel
    raise err
  File "C:\Users\git\.venv\lib\site-packages\sftpretty\__init__.py", line 230, in _sftp_channel
    _channel = SFTPClient.from_transport(self._transport)
  File "C:\Users\git\.venv\lib\site-packages\paramiko\sftp_client.py", line 164, in from_transport
    chan = t.open_session(
  File "C:\Users\git\.venv\lib\site-packages\paramiko\transport.py", line 925, in open_session
    return self.open_channel(
  File "C:\Users\git\.venv\lib\site-packages\paramiko\transport.py", line 1067, in open_channel
    raise e
paramiko.ssh_exception.ChannelException: ChannelException(2, 'Connect failed')

Not sure if this was something being currently worked on or not, just wanted to shed some light on a potential issue. I was able to get pysftp working again on our repo and I can confirm that it did not happen using that dependency, with the same code.

We also noticed ChannelException(1, 'Administratively prohibited') in some instances as well.

byteskeptical commented 1 year ago

I suspect this particular server has a connection limit per user which you are surpassing. If possible you can ask them to bump the number of MaxSessions in sshd_config or at least find out what the limit is to try and avoid it. There maybe a feature request here, perhaps passing in a parameter that sets # of threads on the ThreadPoolExecutor() to try minimize connections.

byteskeptical commented 1 year ago

I should add this is the perfect use-case for the retry decorator. I would start with generous delay and backoff values and slowly work them back down.