-
Notifications
You must be signed in to change notification settings - Fork 542
chore: Handle sftp reconnections #4075
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
a331e1d to
f79c833
Compare
d211516 to
d43bfab
Compare
bindings/sftp/client.go
Outdated
| c.rLock.Lock() | ||
| defer c.rLock.Unlock() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is hard to follow the logic when we have 2 locks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comment to explain why is each lock used, let me know what do you think
bindings/sftp/client.go
Outdated
| msg := strings.ToLower(err.Error()) | ||
| switch { | ||
| case strings.Contains(msg, "use of closed network connection"), | ||
| strings.Contains(msg, "connection reset by peer"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not use typed errors here? syscall.ECONNRESET
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add to the previous if(L230), but I will keep the message here just in case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I modified the method, we will not reconnect if it is one of this errors:
if errors.Is(err, sftpClient.ErrSSHFxPermissionDenied) ||
errors.Is(err, sftpClient.ErrSSHFxNoSuchFile) ||
errors.Is(err, sftpClient.ErrSSHFxOpUnsupported) {
return false
}
Any other error we will try to reconnect
55f5a6a to
90f6d6b
Compare
69d8f53 to
c3594d7
Compare
781c3fc to
edd95a3
Compare
JoshVanL
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am still finding it hard to follow the logic here. We are not locking at the top of functions and we seem to be setting and unsetting need re-connection in multiple places.
7353dde to
a5af6f4
Compare
| if !c.needsReconnect.Load() { | ||
| return nil | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move below lock
bindings/sftp/client.go
Outdated
| pErr := c.ping() | ||
| if pErr != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| pErr := c.ping() | |
| if pErr != nil { | |
| err := c.ping() | |
| if err == nil { | |
| return nil | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if the c.ping works? should we set needsReconnect to false?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, I think so :)
bindings/sftp/client.go
Outdated
| oldSftp := c.sftpClient | ||
| oldSSH := c.sshClient |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for these temp variables.
| oldSftp := c.sftpClient | |
| oldSSH := c.sshClient | |
| if c.sftpClient != nil { | |
| c.sftpClient.Close() | |
| } | |
| if c.sshClient != nil { | |
| c.sshClient.Close() | |
| } |
bindings/sftp/client.go
Outdated
| if c.shouldReconnect(err) { | ||
| c.log.Debugf("sftp binding error: %s", err) | ||
| c.needsReconnect.Store(true) | ||
| } else { | ||
| c.lock.RUnlock() | ||
| return err | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if c.shouldReconnect(err) { | |
| c.log.Debugf("sftp binding error: %s", err) | |
| c.needsReconnect.Store(true) | |
| } else { | |
| c.lock.RUnlock() | |
| return err | |
| } | |
| if !c.shouldReconnect(err) { | |
| c.lock.RUnlock() | |
| return err | |
| } | |
| c.log.Debugf("sftp binding error: %s", err) | |
| c.needsReconnect.Store(true) |
bindings/sftp/client.go
Outdated
| } | ||
| c.lock.RUnlock() | ||
|
|
||
| if c.needsReconnect.Load() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if c.needsReconnect.Load() { |
bindings/sftp/client.go
Outdated
| c.lock.RUnlock() | ||
|
|
||
| if c.needsReconnect.Load() { | ||
| c.log.Debugf("sftp binding: reconnecting to %s", c.address) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move log line inside doReconnect, and only after we have locked and checked nedsReconnect.
78a33bd to
cc88c05
Compare
cicoyle
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
few things from me. Thx!
bindings/sftp/client.go
Outdated
| } | ||
|
|
||
| func withReconnection(c *Client, fn func() error) error { | ||
| c.lock.RLock() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This locking then calling to reconnect then locking again feels like maybe we should have an abstraction function with a for loop where we only lock in that one place versus in a few places. Maybe it could be cleaner if we had a client.do func that had a for loop where we check the client, then do the shouldReconnect and reconnect calls - this way we try reconnecting more than once otherwise, as is we only try once I believe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not want to put more complex mechanism with retries and backoffs, I think this component it may need to be rewritten as some customers requested different improvements. I did a small refactor to introduce a do func where we lock the action 51c4e94
what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree it can be rewritten and improved further. plz open an issue so we dont forget and it can be prioritized at a later date 👍🏻
1afe19b to
72d44bf
Compare
cicoyle
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm, thx Javi!
72d44bf to
a9de6e7
Compare
Signed-off-by: Javier Aliaga <[email protected]>
a9de6e7 to
b83457d
Compare
Signed-off-by: Javier Aliaga <[email protected]>
Description
This PR introduces a re-connection mechanism to the sftp binding.
Issue reference
We strive to have all PR being opened based on an issue, where the problem or feature have been discussed prior to implementation.
Please reference the issue this PR will close: #4061
Checklist
Please make sure you've completed the relevant tasks for this PR, out of the following list:
Note: We expect contributors to open a corresponding documentation PR in the dapr/docs repository. As the implementer, you are the best person to document your work! Implementation PRs will not be merged until the documentation PR is opened and ready for review.