I have a class that represents a custom Task
.
This class has an Execution
method that returns the IEnumerable<string>
of all the inside yield return
statement, and a Start
method that calls the enumerable, thus executing the lazy code.
My problem is that I have also a Stop
method that basically cancels the token associated with the Start
method by using:
TokenSource.CancelAfter(delay);
TokenSource.Token.ThrowIfCancellationRequested();
This code actually stops the running task, but how can I handle the exception? This is not done inside the actual Task
.
Any ideas on how to handle the stop?
An example I've been using to test this part:
public class FunctionTask : Awaitable
{
public FunctionTask(string code, Scheduler scheduler = null)
: base(code, scheduler)
{ }
public override IEnumerable<string> Execution()
{
for (int i = 0; i < 10; i++)
{
yield return WaitFor(TimeSpan.FromSeconds(10d))
.WithDescription($"Step {i + 1}, waiting 1 second");
}
yield return "Done";
}
}
And these are the (inherited) start and stop methods:
public Task Start()
{
stopRequested = false;
Status.Value = TaskStatus.WaitingToRun;
Task task = new Task(() =>
{
Status.Value = TaskStatus.Running;
try
{
// Iterate through the Execution task state
IEnumerable<string> executionState = Execution();
foreach (string state in executionState)
WaitState.Value = state;
// And then through the termination task state
IEnumerable terminationState = Termination();
foreach (string state in terminationState)
WaitState.Value = state;
Status.Value = TaskStatus.RanToCompletion;
}
catch (Exception ex) // This may be caused by a stop request or an actual exception
{
Status.Value = TaskStatus.Faulted;
if (stopRequested)
Logger.Error(ex);
else
Logger.Warn($"Task with code {Code} faulted because a stop has been requested");
}
},
TokenSource.Token
);
task.Start(Scheduler);
return task;
}
public virtual void Stop()
{
if (Status.Value == TaskStatus.Running || Status.Value == TaskStatus.WaitingToRun)
{
stopRequested = true;
TokenSource.Cancel();
TokenSource.Token.ThrowIfCancellationRequested(); // Let the task fail and then stop
Status.Value = TaskStatus.Canceled;
}
}
Use the property IsCancellationRequested if you don't want to throw the OperationCanceledException.
In the Stop method just call TokenSource.Cancel()
and remove the TokenSource.Token.ThrowIfCancellationRequested()
, it doesn't make sense there.
Then use the IsCancellationRequested
property to stop the enumeration, something like:
foreach (string state in executionState)
{
if(token.IsCancelltionRequested)
break;
WaitState.Value = state;
}