clj-ssh
clj-ssh copied to clipboard
Add a timeout option to with-connection
with-connection does not currently allow a timeout specification for making a connection.
Hi! I've seen this issue in production, and it kills my app permanently when it hangs. Would you be open for a PR fixing this? Are there any specific issues that makes it hard? Thanks! :)
If you check how the Util.createSocket is implemented, you will see that the timeout defines an upper limit of the connection only, not a lower limit, because the timeout is strangely not passed to an underlying Socket.Those 20 seconds is probably an OS-level default limit.To override it, try implementing the SocketFactory and attach it to the session using the Session.setSocketFactory.
链接 stackoverflow please close
no timeout and hanging still present in 2019-05
Not sure how to reproduce this issue, but I had a similar problem. All of the worker threads in my app were tied up in the with-connection
call, rendering my app useless until restart.
Here's a potential workaround, in case it benefits anyone.
I noticed in the source that the Session protocol has a two-arity connect
that includes a timeout parameter.
https://github.com/clj-commons/clj-ssh/blob/c50b84275cfc5a1a6b4d837686746f3519eaea12/src/clj_ssh/ssh.clj#L119
It seems to work, but is not being used by thewith-connection
macro.
We can just define our own alternative macro that uses the timeout parameter:
;; "ssh" here is an alias for clj-ssh.ssh, make sure you are requiring that in your ns declaration
(defmacro with-connection-timeout
"Creates a context in which the session is connected. Ensures the session is
disconnected on exit. Will timeout after the provided number of milliseconds if not succesfully connected."
[session timeout & body]
`(let [session# ~session timeout# ~timeout]
(try
(when-not (ssh/connected? session#)
(ssh/connect session# timeout#))
~@body
(finally
(ssh/disconnect session#)))))
You can test this by trying to connect to a non-sftp host:
(let [agent (ssh/ssh-agent {})
sess (ssh/session agent "google.com" {})]
(with-connection-timeout sess 5000
"something!"))
After 5 seconds, it will throw an exception: com.jcraft.jsch.JSchException
with message "timeout: socket is not established"
However, do note that this timeout param only controls the time to connect to the socket. If you do some long-running work inside the body, the timeout param will not prevent that.
For example, if this code connects successfully within 3 seconds, it will then execute the 9 second thread sleep before closing the connection and returning:
(with-connection-timeout sess 3000
(Thread/sleep 9000)
"this took at least 9 seconds to return")
Nice work @brianfay. Thank you