-
When host is not reachable I get following (and expected) timeout error: File "/home/stans/Projects/taro-suite/taroc/taroc/sshclient.py", line 43, in _exec
async with asyncssh.connect(host_info.host, login_timeout=cfg.ssh_con_timeout) as conn:
File "/home/stans/Projects/taro-suite/taroc/venv/lib/python3.9/site-packages/asyncssh/misc.py", line 220, in __aenter__
self._result = await self._coro
File "/home/stans/Projects/taro-suite/taroc/venv/lib/python3.9/site-packages/asyncssh/connection.py", line 6803, in connect
return await _connect(options, loop, flags, conn_factory,
File "/home/stans/Projects/taro-suite/taroc/venv/lib/python3.9/site-packages/asyncssh/connection.py", line 297, in _connect
_, conn = await loop.create_connection(conn_factory, host, port,
File "/usr/lib/python3.9/asyncio/base_events.py", line 1056, in create_connection
raise exceptions[0]
File "/usr/lib/python3.9/asyncio/base_events.py", line 1041, in create_connection
sock = await self._connect_sock(
File "/usr/lib/python3.9/asyncio/base_events.py", line 955, in _connect_sock
await self.sock_connect(sock, address)
File "/usr/lib/python3.9/asyncio/selector_events.py", line 502, in sock_connect
return await fut
File "/usr/lib/python3.9/asyncio/selector_events.py", line 537, in _sock_connect_cb
raise OSError(err, f'Connect call failed {address}')
TimeoutError: [Errno 110] Connect call failed ('172.31.17.30', 22) However it takes about 2 minutes for this exception to be raised (which corresponds to default 2 minutes login timeout). I would need to shorten this interval, so this is what I tried:
However none of these changes has any effect on the actual timeout interval. Is there any other configuration I have to change please? |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 2 replies
-
Is the connect hanging while trying to open the TCP connection? If so, that 2 minutes is not related to the default login timeout. It is a timeout that happens down in the socket layer. On my system, this time is more like 75 seconds, but it varies depending on OS. Right now, the login_timeout only begins to apply once the SSHConnection object is created, which doesn't happen until after the TCP connection completes successfully. Similarly, the timeout argument in the run() method only begins to apply after the SSH handshake completes and you are trying to open a new SSH session on that connection, as run() isn't even called until after the AsyncSSH connect() succeeds. I would have expected two things to work here. The first would be to use socket.setdefaulttimeout() to change the timeout on opening socket connections. However, in a quick test I did here, that doesn't seem to work. The second would have been to wrap the asyncssh.connect() call with an asyncio.wait_for() call without a timeout set. That way, if the connect() takes longer than the timeout, it would cancel the connect and return early. However, that doesn't seem to work either, and I'm not sure why. Since the TCP connect is happening even before most of the asyncssh code is invoked, I'm not sure how much I'll be able to do about this, but I'll look into it further and see if I can figure out what's going on. If I can figure out a way to pass a timeout to the TCP connect code, I might be able to allow login_timeout to be used for this. Right now the processing of login_timeout happens only after the TCP connection is successfully opened as part of the SSHClientConnectionOptions parsing so that would be a bit complicated, but first I need to figure out why the socket level timeout and the wait_for() isn't working in the first place. |
Beta Was this translation helpful? Give feedback.
-
I got a chance to look at this again tonight, and the asyncio.wait_for() approach does work here. I was in a rush when I tested it this morning, and wasn't running the test client I thought I was. Here's an example: import asyncio, asyncssh, sys
async def run_client():
try:
conn = await asyncio.wait_for(asyncssh.connect('10.1.2.3'), timeout=3)
except asyncio.TimeoutError:
sys.exit('Timeout')
async with conn:
print((await conn.run('tty', term_type='ansi')).stdout, end='')
asyncio.run(run_client()) If you don't need to catch the TimeoutError separately for just the connect() call, you can use the asyncio.wait_for() directly in an "async with". For instance: try:
async with await asyncio.wait_for(asyncssh.connect('10.1.2.3'), timeout=3) as conn:
print((await conn.run('tty', term_type='ansi')).stdout, end='')
except asyncio.TimeoutError:
sys.exit('Timeout') However, this stays in the 'try' block even after the connection succeeds, which may not be what you want. In that case, the first example is probably the better one. |
Beta Was this translation helpful? Give feedback.
-
The first example solution is perfect for me. Works like a charm.. |
Beta Was this translation helpful? Give feedback.
-
After multiple requests/questions about this, I've decided to add a new "connect_timeout" parameter that is basically shorthand for wrapping your connect call in asyncio.wait_for(). See #415 for more details about the new option, which is now available as commit b2cadab in the "develop" branch. |
Beta Was this translation helpful? Give feedback.
-
This is now available in AsyncSSH 2.8.1. Let me know if you have any problems with it! |
Beta Was this translation helpful? Give feedback.
I got a chance to look at this again tonight, and the asyncio.wait_for() approach does work here. I was in a rush when I tested it this morning, and wasn't running the test client I thought I was. Here's an example:
If you don't need to catch the TimeoutError separately for just the connect() call, you can use the asyncio.wait_for() directly in an "async with". For inst…