Consider the two following approaches to handling cancellation via CancellationToken:
public async Task DoAllAvailableWork(CancellationToken cancelToken)
{
foreach (var job in GetAllAvailableWork())
{
await job.Process();
if (cancelToken.IsCancellationRequested())
return;
}
}
public async Task DoAllAvailableWork(CancellationToken cancelToken)
{
foreach (var job in GetAllAvailableWork())
{
await job.Process();
cancelToken.ThrowIfCancellationRequested();
}
}
In this case job.Process() is doing some atomic work that should not or cannot be stopped once it begins, so it does not accept a CancellationToken.
Is there any reason to prefer one of these approaches over the other? If yes, which approach should be preferred?
Checking IsCancellationRequested() and returning feels cleaner to me, in the sense that throwing implies something has gone wrong, and cancellation is a case that we explicitly planned to handle (that's why we accept the CancellationToken). On the other hand, the caller can't necessarily know which approach we'll take, so they have to set up a try/catch for OperationCancelledException regardless of which option we choose.