-
Notifications
You must be signed in to change notification settings - Fork 7.1k
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
Wait-Event - Adding -TimeSpan #19705
base: master
Are you sure you want to change the base?
Wait-Event - Adding -TimeSpan #19705
Conversation
src/Microsoft.PowerShell.Commands.Utility/commands/utility/WaitEventCommand.cs
Show resolved
Hide resolved
src/Microsoft.PowerShell.Commands.Utility/commands/utility/WaitEventCommand.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tests are missing
@SteveL-MSFT added a test |
break; | ||
} | ||
|
||
received = _eventArrived.WaitOne(200); | ||
received = _eventArrived.WaitOne((int)(_timeoutTimespan.TotalMilliseconds / 100)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The wait time should be the number of milliseconds until the expiry time occurs. So you wait exactly once, not a hundred times. So before entering the loop determined the point in time when the expiry will occur, each time round the loop calculate the number of milliseconds between now and the expiry time. If the number of milliseconds is negative then you have expired.
If there is no expiry time set then WaitOne() should be used with no expiry time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, it still has to check after each wait to see if the event has arrived. Because this is called in a relatively tight loop, this will probably happen more than once.
After an even comes it, the cmdlet checks to see if it is the correct -SourceIdentifier. If it was, then Wait-Event returns, otherwise, it checks again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That should not be right. It should be completely time independent except for the timeout. The AutoResetEvent _eventArrived should be triggered in NotifyEvent which is called by ReceivedEvents_PSEventReceived which is subscribed by Events.ReceivedEvents.PSEventReceived += ReceivedEvents_PSEventReceived;
So if there is no timeout then you should be able to use WaitOne() because the event will be triggered when there is a change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should not be polling every some arbitrary time period, it should timeout when there is nothing to do, and it should wake up in the loop when an event is received to match the new event.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rhubarb-geek-nz noted, with two additional points:
- The case I'm most concerned about is the rapid timeout or return of a single upcoming event (aka, providing a -Timespan). I believe doing a slightly more efficient job of waiting forever does not help that scenario.
- When the event is triggered, .WaitOne should return as soon as possible. The timespan on .WaitOne is how long to wait before timing out.
If the PowerShell Team requests this change, we can address this. Otherwise, I'd prefer to keep the code change small and the level of intrigue to a minimum, so as to maximize chances of a speedy integration.
/// Negative values mean never timeout. | ||
/// </summary> | ||
[Parameter] | ||
public TimeSpan TimeSpan |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we could change type of Timeout parameter to TimeSpan and add type converter (seconds to TimeSpan) to mitigate the breaking change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be nice if we could, and maybe I'm missing some type converter magic we could use.
When casting [Timespan] from an [int], it casts to ticks, not seconds.
Under the covers I'm turning -TimeOut into -Timespan.
One other thought to avoid having a new parameter would be having -TimeOutSec become a [double], which would allow us to pass, say 0.5.
Unfortunately, I believe this is likely to create some accidental back-compat errors, as scripts with a timeout of 0.25 would run fine on later versions and not wait at all on earlier ones (because of rounding).
IMHO, having a new parameter is a much better hint that it's a newer version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO, having a new parameter is a much better hint that it's a newer version.
If we can use an existing parameter, we should do so. Otherwise it will mislead users, it's bad UX.
PowerShell can do clever things with parameters. You can find examples by searching for ArgumentTransformationAttribute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SteveL-MSFT what's your opinion: would you rather a new parameter or transform the old one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me bring this up to the Cmdlets WG
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SteveL-MSFT / the working group:
I'd like to see this fix go in, as it would fairly immediately improve the performance of working modules.
I'm fairly confident that having two (or more) parameters would be the right way to go here. To restate the reasons:
- Making -TimeoutSec a
[double]
would break back-compat in a weird way, due to rounding. - Making -TimeOutSet a
[TimeSpan]
would create weird casting errors, as ints become 'ticks' in [TimeSpan]s - Making something more complicated to make [TimeSpan] magically castable from [int] might have been nice if it was PowerShell 1, but, as it stands, adding something like a type converter here would potentially break a lot of people's code (and complicate this pull request).
- Adding a -CancellationToken would be desirable, and I believe it should be another PR.
I am trying to keep this PR concise, as I expect to do future work in this space, and I am trying to do one PR per issue.
If there is a solid blocking reason to pend on this, please let me know what it might be, and I'll be happy to make any modifications you need.
To restate the rationale, in the hopes of a speedy resolution:
No one should have to wait a second to find out things didn't work. The faster one can time out a wait for an event that should be effectively immediate, the faster the rest of the code will work.
Please let me know if any adjustments are needed.
Hope this helps,
James
break; | ||
} | ||
|
||
received = _eventArrived.WaitOne(200); | ||
received = _eventArrived.WaitOne((int)(Math.Abs(_timeoutTimespan.TotalMilliseconds) / 100)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not correct. Timeout can accept -1 and no need to divide milliseconds.
This pull request has been automatically marked as Review Needed because it has been there has not been any activity for 7 days. |
@PowerShell/wg-powershell-cmdlets reviewed this, we agree that the desired behavior is for |
This pull request has been automatically marked as Review Needed because it has been there has not been any activity for 7 days. |
This pull request has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 15 days. It will be closed if no further activity occurs within 10 days of this comment. |
@StartAutomating can you review the CodeFactor issues? Also, CI isn't passing. |
This PR has Quantification details
Why proper sizing of changes matters
Optimal pull request sizes drive a better predictable PR flow as they strike a
What can I do to optimize my changes
How to interpret the change counts in git diff output
Was this comment helpful? 👍 :ok_hand: :thumbsdown: (Email) |
Fixed. Please let me know if you'd like some tests on the ArgumentTransform attribute as well. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks pretty good - just looking for 1 additional test for the transform
$stopwatch.ElapsedMilliseconds | Should -BeGreaterThan 200 | ||
$stopwatch.ElapsedMilliseconds | Should -BeLessThan 300 | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should probably have an additional test for the transform. Replicating the test at line 16 with a string value of "00:00:00.25" should do it. I don't think we need a test for a non-convertable value unless you want to validate that you're getting a parameter bind/transform fail error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JamesWTruher a string value would be good.
It's a scenario where we'd need to use a -TransformScript, not just a property name (we'd check to see if it could be a timespan, then pull out the total seconds).
What is the preferred mechanism for using a ScriptBlock as an attribute value within the PowerShell codebase?
Also, Joel Brings up a fair point:
Additionally, I feel it would be very nice if we could make $This in the Transform be the command the ScriptBlock is tied to (but, alas, don't quite know how we'd be able to know that within an attribute). It may also be somewhat nice to have a string property used for metadata about the transform (e.g. a description).
Any ideas on how to make these happen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SeeminglyScience had suggested these be two separate PRs (one for the transform attribute, one for Wait-Event's changes).
As eager as I am to see Wait-Event work with subsecond timeouts (it limits functionality of obs-powershell+ScriptDeck), please let me know if you'd prefer these be separate PRs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@StartAutomating I would agree with @SeeminglyScience that these should be two separate PRs starting with the ArgumentTransform (thanks for taking the feedback and creating it!). It should probably have its own set of tests independent of this cmdlet. Once that one is merged, this PR should be simplified to just use that attribute.
This pull request has been automatically marked as Review Needed because it has been there has not been any activity for 7 days. |
1 similar comment
This pull request has been automatically marked as Review Needed because it has been there has not been any activity for 7 days. |
@SteveL-MSFT thanks for the approval, however, I was still planning on making the [ArgumentTransform] a bit better. If this isn't fully merged, please let me do that this week. |
@StartAutomating removing the community day label until you are ready |
This PR has Quantification details
Why proper sizing of changes matters
Optimal pull request sizes drive a better predictable PR flow as they strike a
What can I do to optimize my changes
How to interpret the change counts in git diff output
Was this comment helpful? 👍 :ok_hand: :thumbsdown: (Email) |
This PR has Quantification details
Why proper sizing of changes matters
Optimal pull request sizes drive a better predictable PR flow as they strike a
What can I do to optimize my changes
How to interpret the change counts in git diff output
Was this comment helpful? 👍 :ok_hand: :thumbsdown: (Email) |
Adding a -TimeSpan parameter to Wait-Event (Fixes #19704). This allows more granularity in waiting on events.
Additionally, changed the polling interval within the command to be 1/100th of the timespan.
These changes improve the performance of Wait-Event substantially, as Wait-Event was always going to wait at least 1/5th of a second.
Due to requests for this to include an argument transformation attribute, this also fixes #20112 .
PR Checklist
.h
,.cpp
,.cs
,.ps1
and.psm1
files have the correct copyright headerWIP:
or[ WIP ]
to the beginning of the title (theWIP
bot will keep its status check atPending
while the prefix is present) and remove the prefix when the PR is ready.(which runs in a different PS Host).