public async Task CancellingAndGracefulShutdown()
{
#region Cancellation AsAbove
var tokenSource = new CancellationTokenSource();
tokenSource.CancelAfter(TimeSpan.FromSeconds(1));
var token = tokenSource.Token;
#endregion
#region Task Tracking AsAbove
var runningTasks = new ConcurrentDictionary<Task, Task>();
#endregion
#region Limiting AsAbove
var semaphore = new SemaphoreSlim(2);
#endregion
var pumpTask = Task.Run(async () =>
{
while (!token.IsCancellationRequested)
{
#region Output
"Pumping...".Output();
#endregion
await semaphore.WaitAsync(token).ConfigureAwait(false);
#region HandleMessage AsAbove
var runningTask = HandleMessageWithCancellation(token);
runningTasks.TryAdd(runningTask, runningTask);
#endregion
#region Releasing Semaphore & Housekeeping AsAbove
runningTask.ContinueWith(t =>
{
#region Output
"... done".Output();
#endregion
semaphore.Release();
#region Housekeeping
Task taskToBeRemoved;
runningTasks.TryRemove(t, out taskToBeRemoved);
#endregion
}, TaskContinuationOptions.ExecuteSynchronously)
.Ignore();
#endregion
}
}, CancellationToken.None);
await pumpTask.IgnoreCancellation().ConfigureAwait(false);
#region Awaiting completion
#region Output
"Pump finished".Output();
#endregion
await Task.WhenAll(runningTasks.Values).IgnoreCancellation().ConfigureAwait(false);
#region Output
"All receives finished".Output();
#endregion
tokenSource.Dispose();
semaphore.Dispose();
#endregion
}