Skip to content

Regression in 6.2.3: Semaphore Disposed Exception thrown in AsyncConsumerWorkService #1153

@ashneilson

Description

@ashneilson

Refer to the original issue for context #1014

Problem

When under load, stopping the AsyncConsumerWorkService can result in System.ObjectDisposedException being thrown due to a Disposed _limiter.

The Discarded Tasks HandleConcurrent started in LoopWithConcurrency may still be running after the finally block disposes of the _limiter Semaphore.

private async Task LoopWithConcurrency(CancellationToken cancellationToken)
{
try
{
while (await _channel.Reader.WaitToReadAsync(cancellationToken).ConfigureAwait(false))
{
while (_channel.Reader.TryRead(out Work work))
{
// Do a quick synchronous check before we resort to async/await with the state-machine overhead.
if (!_limiter.Wait(0))
{
await _limiter.WaitAsync(cancellationToken).ConfigureAwait(false);
}
_ = HandleConcurrent(work, _model, _limiter);
}
}
}
catch (OperationCanceledException)
{
// ignored
}
finally
{
_limiter?.Dispose();
}
}

When the HandleConcurrent Tasks attempt to Release the Semaphore, the System.ObjectDisposedException is thrown.

}
finally
{
work.PostExecute();
limiter.Release();
}

The issue doesn't occur in 6.2.2 but does in 6.2.3. It appears the PR #1113 might be the culprit.

Recommended Fix

I'd be more than happy to submit a PR with a fix if that's the desired approach.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions