Remove 1s minimum delay in Invoke-WebRequest for small files, and prevent file-download-error suppression.#17896
Conversation
|
Open PRs should not be assigned to milestone, so they are not assigned to the wrong milestone after they are merged. For backport consideration, use a |
|
Hmm, looking how Task.Wait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) method works, I think we could refactor the cycle condition (we can not check cancelation since it throws): while (!copyTask.Wait(1000, cancellationToken))
{
record.StatusDescription = StringUtil.Format(WebCmdletStrings.WriteRequestProgressStatus, output.Position);
cmdlet.WriteProgress(record);
};
record.StatusDescription = StringUtil.Format(WebCmdletStrings.WriteRequestComplete, output.Position);
cmdlet.WriteProgress(record); |
In addition to modifying the loop logic, I added a catch for I have tested on mock code here: AAATechGuy/AbinzSharedTools@e9dbe47 |
src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs
Outdated
Show resolved
Hide resolved
|
@AAATechGuy Please rename the PR to something like "Remove 1s minimum delay in Invoke-WebRequest for small files." |
SteveL-MSFT
left a comment
There was a problem hiding this comment.
Agree that we shouldn't ignore download exceptions
|
@AAATechGuy You comment in review mode - open Files changed tab and cancel review mode on top right. Previously we catch and ignore only OperationCanceledException. You added AggregateException - please revert this. |
…Cmdlet/StreamHelper.cs Co-authored-by: Ilya <darpa@yandex.ru>
|
I discussed this with @AAATechGuy and what we agreed is that for 7.3 we should not change the current behavior which is an exception during the copy task is ignored. For 7.4, we should take another change that does not ignore the exception and see if there are any unanticipated side effects as this seems to be the correct change for the long term. |
…lity/WebCmdlet/StreamHelper.cs" This reverts commit d172ef0.
|
My understanding was that we don't ignore exceptions from the copy task. It was my mistake and it is a regression. It is not easy to get an exception from the copy task. I disconnected network for ~1 minutes and restore it. Original cmdlet waits some seconds and silently stop with semi-downloaded file. With the change (without catching AggregateException) user get follow error: I think it is right behavior and we should remove the regression. There is also another issue with CopyToAsync(). If I disconnected network for long time (2 minutes in my experiment) the cmdlet hangs unlimitedly. It is not a problem in interactive scenario since user see a progress bar, but it is huge problem for script scenario since the script can hangs infinitely.
|
|
Talking to @PaulHigin, let's defer taking any change here for 7.3 and make what we agree is the right change (throwing the inner exception from the aggregate) for 7.4 so we have opportunity to see if there's side effects. |
7.3 - no change. 7.4 - we fix two issues: |
daxian-dbw
left a comment
There was a problem hiding this comment.
According to Steve's comment #17896 (comment) (quoted below), the changes from this PR will not be included in 7.3.
Talking to @PaulHigin, let's defer taking any change here for 7.3 and make what we agree is the right change (throwing the inner exception from the aggregate) for 7.4 so we have opportunity to see if there's side effects.
So, we should go with the desired behavior -- throwing inner exceptions from the aggregate exception.
@daxian-dbw , My thought is ... From a PS-user perspective, as @iSazonov tested out here #17896 (comment) , AggregateException does display a sensible error. |
As I understand @SteveL-MSFT, for 7.3 we do semi perf fix with preserving current behavior: try
{
while (!copyTask.Wait(1000, cancellationToken))
{
record.StatusDescription = StringUtil.Format(WebCmdletStrings.WriteRequestProgressStatus, output.Position);
cmdlet.WriteProgress(record);
}
if (copyTask.IsCompleted)
{
record.StatusDescription = StringUtil.Format(WebCmdletStrings.WriteRequestComplete, output.Position);
cmdlet.WriteProgress(record);
}
}
catch (OperationCanceledException)
{
}
catch (AggregateException ae)
{
}and for 7.4 we do full fix: try
{
while (!copyTask.Wait(1000, cancellationToken))
{
record.StatusDescription = StringUtil.Format(WebCmdletStrings.WriteRequestProgressStatus, output.Position);
cmdlet.WriteProgress(record);
}
if (copyTask.IsCompleted)
{
record.StatusDescription = StringUtil.Format(WebCmdletStrings.WriteRequestComplete, output.Position);
cmdlet.WriteProgress(record);
}
}
catch (OperationCanceledException)
{
}
catch (AggregateException)
{
ae.Handle((x) =>
{
return false; // Let all wrapped exceptions throw and be handled in calling layers
});
}and also address second issue (hang) I mentioned above. |
No, That was a previous/ stale suggestion here - comment1. In the latest comment here - comment2, it was discussed, no fix will be taken for 7.3. Hence, the confusion.
Now, for 7.4, I discussed with @PaulHigin and agreed offline, there is no need to catch Hope this clarifies. |
|
We can only throw one exception, so it will have to be the AggregateException, if it contains more than one inner exception. I don't think it is worth checking and we just allow the AggregateException to propagate. |
daxian-dbw
left a comment
There was a problem hiding this comment.
throwing inner exceptions from the aggregate exception, what does this mean - could you suggest a code sample?
I was repeating @SteveL-MSFT's comment and thought that was the conclusion made.
Not catch the exception looks correct to me.
|
@daxian-dbw Can we merge this now or do we wait 7.4? |
|
@iSazonov I believe we've branched for 7.3, so master branch is effectively 7.4 now and should be ok to merge. We cherry pick for 7.3 at this point. |
nice. Can someone help merge this PR then. I don't appear to have permissions. thanks! |
|
@SteveL-MSFT Thanks for clarify! @AAATechGuy thanks for your contribution! Do you have plans to continue with fixing socket timeout #17896 (comment)? |
Thanks for the merge, and for all the reviews, discussions and testing. @iSazonov , no, I don't plan to fix socket timeout issue, at the moment. |
|
/backport to release/v7.2.7 |
|
🎉 Handy links: |

PR Summary
Fix #17893
Both
Invoke-RestMethodandInvoke-WebRequestshowed 20x latency of 1000ms when downloading a web item via pscore 7, that typically takes ~60ms in ps 5, InStreamHelperthere is a constant minimum delay of1sfor any calls toStreamHelper.WriteToStream. This is not expected.If
Invoke-WebRequest/Invoke-RestMethodare used in parallel and for large volume of items, the 1s delay adds up.We fix this issue by replacing
Task.Delaycheck withcopyTask.Wait.The change does take into consideration,
Fix #17931
We also fix the issue where failure in download results in partial file being saved, and exception being suppressed.
PR Context
Tested that perf improves after fix, locally,

Earlier, latency was as follows,

PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:or[ WIP ]to the beginning of the title (theWIPbot will keep its status check atPendingwhile the prefix is present) and remove the prefix when the PR is ready.(which runs in a different PS Host).