I upload for ~10 minutes on 4 different threads and for some reason I always hit a Channel was closed exception. To try and mitigate this I wrote some code to watch for this exception and attempt to throw away my sftpclient object and reconnect. However when I call .Connect(), I STILL get "Channel was closed" even after disposing and nulling my SftpClient object. Clearly I'm doing something wrong. Any ideas?
```
Code for sftpclient management: one per thread
protected SftpClient Client
{
get
{
SftpClient client;
if (!this.clients.TryGetValue(Thread.CurrentThread, out client))
{
client = new SftpClient(this.host, SftpUserName, this.privateKeyFile);
this.clients[Thread.CurrentThread] = client;
}
// For now only do one of these at a time
lock (this.connectionLock)
{
if (!client.IsConnected)
{
this.LogContext.LogInfo("Connecting client for thread " + Thread.CurrentThread.ManagedThreadId);
client.Connect();
}
}
return client;
}
}
// Detect and attempt to refresh connection
protected void RefreshConnectionOnSshException(Action action)
{
int retryLimit = 2;
for (int retries = 0; retries <= retryLimit; retries++)
{
try
{
action();
break;
}
catch (SshException err)
{
if (retries < retryLimit)
{
this.LogContext.LogWarning("SshException was thrown. Disposing the SftpClient and letting a new one be created: " + err.Message);
this.clients[Thread.CurrentThread].Dispose();
this.clients.Remove(Thread.CurrentThread);
Thread.Sleep(BaseManager.RetryIntervalMilliseconds);
}
else
{
throw;
}
}
}
}
// Sample copy instruction
protected override void InternalPerformCopyInstruction(CopyInstruction instruction)
{
var fi = new FileInfo(instruction.SourceFileName);
using (Stream file = fi.OpenRead())
{
string destination = this.CleanRemotePath(instruction.DestFileName);
if (this.FileExists(destination))
{
this.LogContext.LogInfo("Destination already exists. Deleting before upload: " + destination);
this.RefreshConnectionOnSshException(() => this.Client.DeleteFile(destination));
}
this.LogContext.LogInfo("Securely uploading file: " + destination);
this.RefreshConnectionOnSshException(() => this.Client.UploadFile(file, destination));
this.LogContext.LogInfo("Completed uploading file: " + destination);
}
}
```
Then I hit an error that looks like this:
2014-10-07T03:16:11.951Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Warning,SshException was thrown. Disposing the SftpClient and letting a new one be created: Channel was closed.
2014-10-07T03:16:15.073Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Information,Connecting client for thread
2014-10-07T03:16:15.681Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Warning,SshException was thrown. Disposing the SftpClient and letting a new one be created: Channel was closed.
2014-10-07T03:16:18.802Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Information,Connecting client for thread
2014-10-07T03:16:19.394Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Error,"Exception has occurred:Renci.SshNet.Common.SshException: Channel was closed. at Renci.SshNet.Sftp.SubsystemSession.WaitOnHandle(WaitHandle waitHandle, TimeSpan operationTimeout) at __Renci.SshNet.Sftp.SftpSession.OnChannelOpen()__ at Applications..SftpCopy.get_Client() in .\SftpCopy.cs:line 98
Comments: ** Comment from web user: fancycat **
Hi drieseng. Thanks for getting back to me so quickly.
I can probably gather logs from the FTP server. While I work on that, a few questions:
Do I need to be doing anything to keep the SSH channel alive? Is it ok that I'm using four threads and four different sftpclient objects concurrently? When the channel dies, do you have suggestions about how I might open it back up cleanly? I have a suspicion that after I detect something wrong with the ssh channel, my call to dispose the dead sftpclient may be throwing.
```
this.LogContext.LogWarning("SshException was thrown. Disposing the SftpClient and letting a new one be created: " + err.Message);
this.clients[Thread.CurrentThread].Dispose(); // <--- throwing??
this.clients.Remove(Thread.CurrentThread);
```