Best way to use Session object in critical Windows services
Hi,
i'd like to have some guidelines regarding Session object usage in critical Windows services.
Our service runs every 30 mins and have to upload\download some remote files in the most stable way possible. The service must not leak memory nor experiment connection floods or hangs (in particular the latest is a common issue in SFTP\FTP libraries, this one too, and i totally need to avoid it). What's the best way to use WinSCP in order to avoid issues and experience the best stability?
My idea was to create a unique Session object that lives\dies for each single service spin (so every 30 minutes) and does each upload\download in a "safe" method that each time checks connection state and eventually disconnect\recreate\reconnect the instance in case of connection issues. In this way the client connects to remote host fewer times, reducing the risk of connection problems (hang up in particular). This is an example of the Upload() method i've implemented:
Is it a stable approach?
Or should i create a Session for each file that i have to upload\download like this pseudocode?
Another option to avoid freezing issues would be to surround SafeExec() in a thread with a long timeout. If the socket get stuck it won't lock the main thread and the service can continue. In order to do this, the Session object needs to be thread safe and each Session instance must not be affected by other inconsistent or stuck Session objects (so Session objects doens't have to have static shared state variables). Is it a valid way in your opinion?
Have you got some ideas to point me on the right way?
Thank you very much.
i'd like to have some guidelines regarding Session object usage in critical Windows services.
Our service runs every 30 mins and have to upload\download some remote files in the most stable way possible. The service must not leak memory nor experiment connection floods or hangs (in particular the latest is a common issue in SFTP\FTP libraries, this one too, and i totally need to avoid it). What's the best way to use WinSCP in order to avoid issues and experience the best stability?
My idea was to create a unique Session object that lives\dies for each single service spin (so every 30 minutes) and does each upload\download in a "safe" method that each time checks connection state and eventually disconnect\recreate\reconnect the instance in case of connection issues. In this way the client connects to remote host fewer times, reducing the risk of connection problems (hang up in particular). This is an example of the Upload() method i've implemented:
private SessionOptions _sessionOptions; private Session _client; private Upload(Dictionary<string, string> fileList) { foreach(var file in fileList) { SafeExec(() => { _client.PutFiles(file.Key, file.Value); }); } } private void SafeExec(Action action) { // Check client state if (_client == null || !_client.Opened) { // If client connection is not open, explicitly close it and dispose the instance if (this._client != null) { this._client.Close(); this._client.Failed -= _client_Failed; this._client.Dispose(); this._client = null; } // Recreate instance var sessionOptions = new SessionOptions { Protocol = Protocol.Sftp, HostName = this.host, UserName = this.username, Password = this.password, PortNumber = this.port, GiveUpSecurityAndAcceptAnySshHostKey = true }; this._client = new Session(); this._client.ExecutablePath = Path.Combine(GetExecutionFilePath(), "WinSCP.exe"); // set WinSCP.exe path this._client.SessionLogPath = Path.Combine(GetExecutionFilePath(), "Log\\WinScp.log"); // set session log for issue tracing this._client.Failed += _client_Failed; // Intercept event for internal logging // Open instance _client.Open(this._sessionOptions); } // If client is open, execute my delegate if (_client.Opened) action.Invoke(); else throw new SafeExecClientDisconnected(); }
Is it a stable approach?
Or should i create a Session for each file that i have to upload\download like this pseudocode?
private Upload(Dictionary<string, string> fileList) { foreach(var file in fileList) { using(var session = new Session(...)) { session.Open(...); _client.PutFiles(file.Key, file.Value); } } }
Another option to avoid freezing issues would be to surround SafeExec() in a thread with a long timeout. If the socket get stuck it won't lock the main thread and the service can continue. In order to do this, the Session object needs to be thread safe and each Session instance must not be affected by other inconsistent or stuck Session objects (so Session objects doens't have to have static shared state variables). Is it a valid way in your opinion?
private SessionOptions _sessionOptions; private Session _client; private Upload(Dictionary<string, string> fileList) { foreach(var file in fileList) { AsyncSafeExec(() => { _client.PutFiles(file.Key, file.Value); }); } } private void AsyncSafeExec(Action action) { var task = Task.Factory.StartNew(() => SafeExec(action)); try { if(!task.Wait(3600000)) throw new Exception(); // 1 hour timeout } catch { // Ignores exceptions or timeouts _client = null; // Forces client creation for the next call } }
Have you got some ideas to point me on the right way?
Thank you very much.