-
Notifications
You must be signed in to change notification settings - Fork 7.8k
Closed
Labels
In-PRIndicates that a PR is out for the issueIndicates that a PR is out for the issueIssue-Enhancementthe issue is more of a feature request than a bugthe issue is more of a feature request than a bugWG-Enginecore PowerShell engine, interpreter, and runtimecore PowerShell engine, interpreter, and runtime
Description
Summary of the new feature / enhancement
A common pattern for binary cmdlets is to create a cancellation token source that is then cancelled in PSCmdlet.StopProcessing()
.
This is a very useful pattern to enable cancelling a method that takes CancellationToken
without having to poll for completion. Having this available by default would reduce a lot of boilerplate in binary cmdlets. Boilerplate example:
namespace MyModule;
[Cmdlet(VerbsDiagnostic.Test, "MyCommand")]
public class TestMyCommand : PSCmdlet, IDisposable
{
private readonly CancellationTokenSource _stopping = new();
protected override void ProcessRecord()
{
try
{
Task.Delay(2000, _stopping.Token).GetAwaiter().GetResult();
}
catch (OperationCancelledException)
{
throw new PipelineStoppedException();
}
}
protected override void StopProcessing() => _stopping.Cancel();
public void Dispose() => _stopping.Dispose();
}
This pattern is not possible in PowerShell directly, instead a script must poll a task for completion if it wants to respect pipeline stops. Polling example:
$task = [System.Threading.Tasks.Task]::Delay(2000)
while (-not $task.AsyncWaitHandle.WaitOne(200)) { }
$null = $task.GetAwaiter().GetResult();
Even then all you can do is honor pipeline stops, you can't request cancellation of the work being done in another thread.
Proposed technical implementation details (optional)
namespace System.Management.Automation;
public abstract class PSCmdlet
{
+ private CancellationTokenSource? _pipelineStopTokenSource;
+ public CancellationToken PipelineStopToken => (_pipelineStopTokenSource ??= new()).Token;
protected virtual void StopProcessing()
{
using (PSTransactionManager.GetEngineProtectionScope())
{
+ _pipelineStopTokenSource?.Cancel();
}
}
internal void InternalDispose(bool isDisposing)
{
_myInvocation = null;
_state = null;
_commandInfo = null;
_context = null;
+ _pipelineStopTokenSource?.Dispose();
+ _pipelineStopTokenSource = null;
}
}
vexx32, jborean93, fMichaleczek, santisq, PaulHigin and 9 more
Metadata
Metadata
Assignees
Labels
In-PRIndicates that a PR is out for the issueIndicates that a PR is out for the issueIssue-Enhancementthe issue is more of a feature request than a bugthe issue is more of a feature request than a bugWG-Enginecore PowerShell engine, interpreter, and runtimecore PowerShell engine, interpreter, and runtime