-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Fix starvation issue with session processor when MaxCallsPerSession > 1 #14937
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,6 +36,8 @@ internal class SessionReceiverManager : ReceiverManager | |
| private CancellationTokenSource _sessionLockRenewalCancellationSource; | ||
| private Task _sessionLockRenewalTask; | ||
| private CancellationTokenSource _sessionCancellationSource = new CancellationTokenSource(); | ||
| private bool _receiveTimeout; | ||
|
|
||
| protected override ServiceBusReceiver Receiver => _receiver; | ||
|
|
||
| private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); | ||
|
|
@@ -80,7 +82,11 @@ private async Task<bool> EnsureCanProcess(CancellationToken cancellationToken) | |
| { | ||
| await WaitSemaphore(cancellationToken).ConfigureAwait(false); | ||
| releaseSemaphore = true; | ||
| if (_threadCount >= _maxCallsPerSession) | ||
| if (_threadCount >= _maxCallsPerSession || | ||
| // If a receive call timed out for this session, avoid adding more threads | ||
|
||
| // if we don't intend to leave the receiver open on receive timeouts. This | ||
| // will help ensure other sessions get a chance to be processed. | ||
| (_receiveTimeout && !_keepOpenOnReceiveTimeout)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
@@ -185,7 +191,7 @@ public override async Task CloseReceiverIfNeeded( | |
| _threadCount--; | ||
| if (_threadCount == 0 && !processorCancellationToken.IsCancellationRequested) | ||
| { | ||
| if (!_keepOpenOnReceiveTimeout || | ||
| if ((_receiveTimeout && !_keepOpenOnReceiveTimeout) || | ||
| !AutoRenewLock || | ||
| _sessionLockRenewalCancellationSource.IsCancellationRequested) | ||
| { | ||
|
|
@@ -234,6 +240,7 @@ await RaiseExceptionReceived( | |
| // Always at least attempt to dispose. If this fails, it won't be retried. | ||
| await _receiver.DisposeAsync().ConfigureAwait(false); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the dispose fails, should
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, similar to how we don't allow retrying close on sender/receiver, if the close here fails the processor will not retain a reference to the receiver and we expect the service to close the link after the idle timeout of 10 minutes. |
||
| _receiver = null; | ||
| _receiveTimeout = false; | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -269,6 +276,7 @@ public override async Task ReceiveAndProcessMessagesAsync(CancellationToken proc | |
| { | ||
| // Break out of the loop to allow a new session to | ||
| // be processed. | ||
| _receiveTimeout = true; | ||
| break; | ||
| } | ||
| await ProcessOneMessageWithinScopeAsync( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to guard against null here for
sessionId?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so.. passing null sessionId seems to be fine.