Skip to content

Invoke-Restmethode won't timeout #12249

Closed

Description

@KrX3D

Steps to reproduce

Hello,

i got this code here for demonstration:

Invoke-RestMethod -uri "https://XXXXXX.blob.core.windows.net/XXXXXXXX/XXXXXX/SOURCES/PE10.WIM?st=2020-02-20T13%3A08%3A43Z&se=2021-02-21T13%3A08%3A00Z&sp=racwdl&sv=2018-03-28&sr=b&sig=SIGNATURE" -OutFile "C:\Users\testUser\Downloads\DL\PRG\test.wim"

when i use that code i can get the download.
Firstly to maybe make clear what the parameter TimeoutSec should do. i thought it the connection stops i get an timeout after 10 seconds? or do i get an timeout after 10 seconds when i cant get an answer ?

To the problem: when i use that code above the download starts with Powershell 7. When i unplug my Lan cable when the download is already progressing, i can reattach the cable in maybe 10 seconds and the download resumes. when i leave it unpluged this happens:

in Powershell 5: i get an timeout after 5 minutes. and the script goes on (thats what i want)
in Powershell 7: nothing happens, waiting 5, 10 minutes, even hours (tested till 1 day) and its stuck. also the script is stuck and wont progress anymore

Expected behavior

  • after the connection is lost during an download (or cable is unpluged) a timeout should happen after 5 minutes, like it happens in Powershell 5

# Actual behavior

- Powershell 7 is stuck during the download when cable is unpluged. Script hangs forever

Environment data


Activity

  1. added
    Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a
    on Apr 3, 2020
  2. iSazonov commented on Apr 4, 2020

    @iSazonov
    Collaborator

    KrX3D Please share PSVertionTable as issue template requested.
    Also please test with latest build PowerShell 7.1 Preview1.

  3. KrX3D commented on Apr 6, 2020

    @KrX3D
    Author

    Ah sorry here it is for PS7 which does not work:

    Name Value

    PSVersion 7.0.0
    PSEdition Core
    GitCommitId 7.0.0
    OS Microsoft Windows 10.0.14393
    Platform Win32NT
    PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
    PSRemotingProtocolVersion 2.3
    SerializationVersion 1.1.0.1
    WSManStackVersion 3.0

    And here for PS5 which does work:

    Name Value

    PSVersion 5.1.14393.3471
    PSEdition Desktop
    PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
    BuildVersion 10.0.14393.3471
    CLRVersion 4.0.30319.42000
    WSManStackVersion 3.0
    PSRemotingProtocolVersion 2.3
    SerializationVersion 1.1.0.1

  4. iSazonov commented on Apr 6, 2020

    @iSazonov
    Collaborator

    Please check with 7.1 Preview1

  5. KrX3D commented on Apr 6, 2020

    @KrX3D
    Author

    i tried it with the preview version. Still the same problem:

    Name Value

    PSVersion 7.1.0-preview.1
    PSEdition Core
    GitCommitId 7.1.0-preview.1
    OS Microsoft Windows 10.0.14393
    Platform Win32NT
    PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
    PSRemotingProtocolVersion 2.3
    SerializationVersion 1.1.0.1
    WSManStackVersion 3.0

  6. added
    Issue-BugIssue has been identified as a bug in the product
    and removed
    Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a
    on Apr 6, 2020
  7. KrX3D commented on Jun 3, 2020

    @KrX3D
    Author

    Hello,
    anything new about this problem?

  8. iSazonov commented on Jun 3, 2020

    @iSazonov
    Collaborator

    I think it is easy to implement.
    The method

    internal static void WriteToStream(Stream input, Stream output, PSCmdlet cmdlet, CancellationToken cancellationToken)

    accept a cancelation token so CancellationTokenSource could be initialized with a default timeout like 300 seconds.

  9. added
    Up-for-GrabsUp-for-grabs issues are not high priorities, and may be opportunities for external contributors
    on Jun 3, 2020
  10. vexx32 commented on Jun 3, 2020

    @vexx32
    Collaborator

    We should also ensure that -TimeoutSec is respected there as well, but a sensible default would be wise.

  11. iSazonov commented on Jun 3, 2020

    @iSazonov
    Collaborator

    TimeoutSec is used in HttpClient as connection timeout.

  12. KrX3D commented on Jun 4, 2020

    @KrX3D
    Author

    ok, but still the Invoke-Rest Comand should timeout after 5 minutes in PS7 like it does in PS5 and not hang for eternity

  13. KrX3D commented on Jul 22, 2020

    @KrX3D
    Author

    i updated my first post and removed the timeout parameter.
    but like i said, with no connection the invoke-restmethode function is stuck in powershell 7 (tested with 7.0.3) and in PS5 it just "timeouts" after 5 minutes and my script can go on

  14. 10 remaining items

  15. ghost removed
    In-PRIndicates that a PR is out for the issue
    on Mar 12, 2023
  16. iSazonov commented on Mar 13, 2023

    @iSazonov
    Collaborator

    Ilya (@iSazonov) you stated the TimeoutSec is only used for the connection timeout. Should we add a second timeout for receiving data (e.g. ReceiveTimeout) with a reasonably high default (e.g. 5 minutes to make it similar to PS 5.1)? and pass that cancellation token to the stream handling routines?

    I said about HttpClient implementation.
    PowerShell docs say about the parameter:

    Specifies how long the request can be pending before it times out

    I take it that if during any operation any request hangs for this time (network loss), then the cmdlet should terminate.
    The .Net does not seem to support this (at least in HttpClient).
    So we could only implement Ctrl-C, the easiest way is to put everything into a new task with separate CTS.

  17. stevenebutler commented on Mar 14, 2023

    @stevenebutler
    Contributor

    Ilya (@iSazonov) it should be possible to do this without using a separate task provided the cancellation token we already have is passed through to low levels. I believe my WIP PR already demonstrates this for the CTRL-C issue and will need some additional work to support timing out when no traffic is received for a period of time (TimeoutSec).

    The reason HttpClient timeout is not in play anymore is because once data is being read from the stream directly, the HttpClient API is no longer being used. The streams APIs used to do this have cancellation support if the Async APIs are used, so it is possible to implement timeouts using the cancellation token while reading from the streams.

    Because of this I don't think the CmdLet needs to, or even should use a separate task to support cancellation and timeouts.

    If the task is cancelled it will return to the user, but unless the cancellation token also cancels the underlying operations, they will continue even though the cmdlet appears to be finished. If the cancellation token is passed down to those underlying operations instead, when the cancellation token is cancelled it will abort the underlying operations.

    The trick with this issue is that rather than using a straight timeout, the cancellation token timeout needs to be reset whenever data is received on the connection. If the cancellation token source is available to the underlying layers that are reading from the socket, it is possible to reset the timeout every time data is read by calling cts.CancelAfter(timeoutVal).

    The second problem with using a task in the cmdlet is it will not be able to write progress or output to the stream from that task directly since it will likely be running in a separate thread and PowerShell does not support using WriteXXX APIs outside the main thread if I recall correctly.

    I haven't tried to implement this as I'd like to work on PR #19315 which is simpler and fixes the CTRL-C support first before implementing a fix for this issue in the interests of keeping the PR small and easier to review.

  18. iSazonov commented on Mar 15, 2023

    @iSazonov
    Collaborator

    The problem is that when we pass a CTS into the .Net API it does not guarantee that this CTS will work as we expect, because there can be many layers within that API.
    In particular I discussed this problem for the HttpClient in the .Net Runtime repository. But the same problem could be with any other API.
    So it doesn't make sense to convert the code to async and distribute CTS. Eventually it will fix all the problems and will unpredictably depend on the implementation in .Net.
    What we can do is explicitly solve the problem at hand. In particular, add support for Ctrl-C.

  19. stevenebutler commented on Mar 15, 2023

    @stevenebutler
    Contributor

    The .NET APIs that take cancellation tokens do work with the cancellation token. The issue you're describing is that HttpClient and handler, take timeouts properties but don't cancel the request when they are no longer effectively controlling them because they have handed off the response stream to be read independently. The HttpClient is not providing cancellation token to the underlying stream to cancel them because it is not reading them. The streams APIs take the cancellation token in the supported API calls and don't save a reference to the token so if they are read without passing a token they cannot be cancelled. When reading the streams if no cancellation token is passed to them, they have no way of being cancelled.

    If a separate task is used, how would the supervisor then monitor the stream for activity so it can reset the cancellation timeout whenever traffic is received? The requirement is for a timeout on no stream activity over a period of time (the TimeoutSec), not a straight-forward timeout from the start of the response.

    .NET core onwards is heavily biased towards cancellable asynchronous APIs so we should take advantage of them where it makes sense.

    Please have a look at PR#19330 which uses the cancellable APIs to make CTRL-C work. With some additional logic to reset the cancellation token timeout whenever data is read from the stream it should be possible to do similar for this issue.

  20. iSazonov commented on Mar 16, 2023

    @iSazonov
    Collaborator

    The .NET APIs that take cancellation tokens do work with the cancellation token.

    They work. But not always as you expected. See dotnet/runtime#74568
    In other words, your PR does not solve the Ctrl-C problem completely.
    And if so, it is better not to complicate the code and apply a more universal solution.

  21. ghost added
    In-PRIndicates that a PR is out for the issue
    on Apr 23, 2023
  22. ghost removed
    In-PRIndicates that a PR is out for the issue
    on Apr 27, 2023
  23. ghost added
    In-PRIndicates that a PR is out for the issue
    on Apr 27, 2023
  24. ghost removed
    In-PRIndicates that a PR is out for the issue
    on Jun 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Hacktoberfest-AcceptedAccepted to participate in HacktoberfestIssue-BugIssue has been identified as a bug in the productResolution-FixedThe issue is fixed.WG-Cmdletsgeneral cmdlet issues

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions