I'm not sure if I'm stopping a Parallel.ForEach
loop as I intend to do.
So let me outline the problem.
The loop uses a database driver with limited available connections and it is required to keep track of the open connections, so the database driver doesn't throw an exception. The issue is that keeping track of open connections has been implemented manually (this should be refactored - writing a wrapper or using AutoResetEvent
but there are some other things that need to be taken care of first). So I need to keep track of the open connections and especially I have to handle the case of an exception:
Parallel.ForEach(hugeLists, parallelOptions, currentList => {
WaitForDatabaseConnection();
try {
Interlocked.Increment(ref numOfOpenConnections);
DoDatabaseCallAndInsertions();
} catch (Exception ex) {
// logging
throw;
} finally {
Interlocked.Decrement(ref numOfOpenConnections);
}
}
This is the simplified version of the loop without cancellation. To improve the performance in case of an Exception the loop should be cancelled as soon as possible when an Exception is thrown. If one thing fails the loop should stop.
How can I achieve that making sure that numOfOpenConnections
is being updated correctly?
What I have tried so far (is this behaving like I want it to or am I missing something?):
Parallel.ForEach(hugeLists, parallelOptions, (currentList, parallelLoopState) => {
parallelOptions.CancellationToken.ThrowIfCancellationRequested();
WaitForDatabaseConnection();
try {
Interlocked.Increment(ref numOfOpenConnections);
DoDatabaseCallAndInsertions();
} catch (Exception ex) {
// logging
cancellationTokenSource.Cancel();
parallelLoopState.Stop();
throw; // still want to preserve the original exception information
} finally {
Interlocked.Decrement(ref numOfOpenConnections);
}
}
I could wrap this code in a try - catch construct and catch AggregateException
.