Skip to content
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

Add ExecuteAsync, Fix CancelAsync Deadlock #1343

Closed
wants to merge 3 commits into from

Conversation

zeotuan
Copy link
Contributor

@zeotuan zeotuan commented Mar 5, 2024

@zeotuan zeotuan marked this pull request as ready for review March 5, 2024 02:51
@zeotuan zeotuan force-pushed the develop branch 2 times, most recently from 751d5ad to c04d6fb Compare March 5, 2024 09:10
@zeotuan zeotuan marked this pull request as draft March 5, 2024 10:39
zeotuan and others added 3 commits March 6, 2024 22:03
* Add ExecuteAsync with cancellation

* Deprecate Error and Result property

* Fix Deadlock with cancel Async
@zeotuan zeotuan marked this pull request as ready for review March 6, 2024 11:03

try
{
var status = await Task<int>.Factory.FromAsync(BeginExecute(), EndExecuteWithStatus).ConfigureAwait(false);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to add Async overloaded methods but I think this is not a real async code. I've prepared a POC here: #1318

I know that your approach is easier to implement, but this is similar to nuget: https://www.nuget.org/packages/Renci.SshNet.Async#versions-body-tab

You can find code here: https://github.com/JohnTheGr8/Renci.SshNet.Async/blob/master/Renci.SshNet.Async/SshNetExtensions.cs

@@ -105,56 +107,72 @@ public Stream CreateInputStream()
/// <summary>
/// Gets the command execution result.
/// </summary>
#pragma warning disable S1133 // Deprecated code should be removed
[Obsolete("Please read the result from the OutputStream. I.e. new StreamReader(shell.OutputStream).ReadToEnd().")]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should we make it obsolete?

}

/// <summary>
/// Gets the command execution error.
/// </summary>
#pragma warning disable S1133 // Deprecated code should be removed
[Obsolete("Please read the error result from the ExtendedOutputStream. I.e. new StreamReader(shell.ExtendedOutputStream).ReadToEnd().")]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should we make it obsolete?

@Rob-Hague
Copy link
Collaborator

@WojciechNagorski commented just as I was commenting some similar feedback, so sorry for the duplication 🙂 :

I think you are still working on this so just some high-level thoughts:

There are a few semi-related changes here. The cancellation via signal is good. I would suggest splitting that to a standalone PR to start with.

I understand the reason for obsoleting the Result/Error properties (because they consume the stream properties) but I do not think the change is justified. Especially given how many changes it causes just in our own code (forwarding to a now internal version at that). I would suggest reverting that.

I'm a little uneasy about using TaskFactory.FromAsync in this library because many of the Begin/End (APM) methods are not implemented so well and we end up spawning new threads/blocking on more threads than we need. I basically share the same sentiment as #931 (comment). But at first glance it is not so bad here.

@zeotuan
Copy link
Contributor Author

zeotuan commented Mar 6, 2024

@Rob-Hague @WojciechNagorski Very Interesting. I would love to help with the project.

https://www.nuget.org/packages/Renci.SshNet.Async#versions-body-tab unfortunately does not support CancellationToken.
So I was thinking of adding a simple TAP over APM wrapper here until we get a proper TAP rewrite.

I also expect the execution of command to leave the OutputStream and ExtendedOutputStream intact and provide my own way to consuming them. for example: I want to forward the stdout and stderr to another program while the command is being executed not after.

Therefore, I would suggest Future ExecuteAsync Implementation to at least just return an exit status code instead of consuming those stream. Also Providing a public helper method to let people get Result/Error from those stream. It would require refactoring for any downstream project that will migrate to Async anyway

I have submitted a standalone PR for CancelAsync: #1345

@WojciechNagorski
Copy link
Collaborator

@zeotuan Sory for the delay. If you want you can continue to help us add true asynchronous methods. let us know.

@zeotuan
Copy link
Contributor Author

zeotuan commented Mar 22, 2024

@WojciechNagorski Hi! Yes, I would like to help with adding true async methods for sshnet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants