private void EnsureRequestsAreHandled()
{
if (_processingRequests)
{
return;
}
if (!_channels.Any() && _channelConfig.InitialChannelCount > 0)
{
_logger.LogInformation("Currently no available channels.");
return;
}
lock (_processLock)
{
if (_processingRequests)
{
return;
}
_processingRequests = true;
_logger.LogDebug("Begining to process 'GetChannel' requests.");
}
TaskCompletionSource<IModel> channelTcs;
while (_requestQueue.TryDequeue(out channelTcs))
{
lock (_channelLock)
{
if (_current == null && _channelConfig.InitialChannelCount == 0)
{
CreateAndWireupAsync().Wait();
_current = _channels.First;
}
_current = _current.Next ?? _channels.First;
if (_current.Value.IsOpen)
{
channelTcs.TrySetResult(_current.Value);
continue;
}
_logger.LogInformation($"Channel '{_current.Value.ChannelNumber}' is closed. Removing it from pool.");
_channels.Remove(_current);
if (_current.Value.CloseReason.Initiator == ShutdownInitiator.Application)
{
_logger.LogInformation($"Channel '{_current.Value.ChannelNumber}' is closed by application. Disposing channel.");
_current.Value.Dispose();
if (!_channels.Any())
{
var newChannelTask = CreateAndWireupAsync();
newChannelTask.Wait();
_current = _channels.Last;
channelTcs.TrySetResult(_current.Value);
continue;
}
}
}
var openChannel = _channels.FirstOrDefault(c => c.IsOpen);
if (openChannel != null)
{
_logger.LogInformation($"Using channel '{openChannel.ChannelNumber}', which is open.");
channelTcs.TrySetResult(openChannel);
continue;
}
var isRecoverable = _channels.Any(c => c is IRecoverable);
if (!isRecoverable)
{
_processingRequests = false;
throw new ChannelAvailabilityException("Unable to retreive channel. All existing channels are closed and none of them are recoverable.");
}
_logger.LogInformation("Unable to find an open channel. Requeue TaskCompletionSource for future process and abort execution.");
_requestQueue.Enqueue(channelTcs);
_processingRequests = false;
return;
}
_processingRequests = false;
_logger.LogDebug("'GetChannel' has been processed.");
}