internal SessionClient( string clientTypeName, string entityPath, MessagingEntityType?entityType, ReceiveMode receiveMode, int prefetchCount, ServiceBusConnection serviceBusConnection, ITokenProvider tokenProvider, ICbsTokenProvider cbsTokenProvider, RetryPolicy retryPolicy, IList <ServiceBusPlugin> registeredPlugins) : base(clientTypeName, entityPath, retryPolicy ?? RetryPolicy.Default) { this.ServiceBusConnection = serviceBusConnection ?? throw new ArgumentNullException(nameof(serviceBusConnection)); this.EntityPath = entityPath; this.EntityType = entityType; this.ReceiveMode = receiveMode; this.PrefetchCount = prefetchCount; tokenProvider = tokenProvider ?? this.ServiceBusConnection.CreateTokenProvider(); this.CbsTokenProvider = cbsTokenProvider ?? new TokenProviderAdapter(tokenProvider, this.ServiceBusConnection.OperationTimeout); this.diagnosticSource = new ServiceBusDiagnosticSource(entityPath, serviceBusConnection.Endpoint); // Register plugins on the message session. if (registeredPlugins != null) { foreach (var serviceBusPlugin in registeredPlugins) { this.RegisterPlugin(serviceBusPlugin); } } }
/// <summary> /// Creates a new instance of the Subscription client on a given <see cref="ServiceBusConnection"/> /// </summary> /// <param name="serviceBusConnection">Connection object to the service bus namespace.</param> /// <param name="topicPath">Topic path.</param> /// <param name="subscriptionName">Subscription name.</param> /// <param name="receiveMode">Mode of receive of messages. Defaults to <see cref="ReceiveMode"/>.PeekLock.</param> /// <param name="retryPolicy">Retry policy for subscription operations. Defaults to <see cref="RetryPolicy.Default"/></param> public SubscriptionClient(ServiceBusConnection serviceBusConnection, string topicPath, string subscriptionName, ReceiveMode receiveMode, RetryPolicy retryPolicy) : base(nameof(SubscriptionClient), $"{topicPath}/{subscriptionName}", retryPolicy) { if (string.IsNullOrWhiteSpace(topicPath)) { throw Fx.Exception.ArgumentNullOrWhiteSpace(topicPath); } if (string.IsNullOrWhiteSpace(subscriptionName)) { throw Fx.Exception.ArgumentNullOrWhiteSpace(subscriptionName); } MessagingEventSource.Log.SubscriptionClientCreateStart(serviceBusConnection?.Endpoint.Authority, topicPath, subscriptionName, receiveMode.ToString()); this.ServiceBusConnection = serviceBusConnection ?? throw new ArgumentNullException(nameof(serviceBusConnection)); this.syncLock = new object(); this.TopicPath = topicPath; this.SubscriptionName = subscriptionName; this.Path = EntityNameHelper.FormatSubscriptionPath(this.TopicPath, this.SubscriptionName); this.ReceiveMode = receiveMode; this.diagnosticSource = new ServiceBusDiagnosticSource(this.Path, serviceBusConnection.Endpoint); this.OwnsConnection = false; this.ServiceBusConnection.ThrowIfClosed(); if (this.ServiceBusConnection.TokenProvider != null) { this.CbsTokenProvider = new TokenProviderAdapter(this.ServiceBusConnection.TokenProvider, this.ServiceBusConnection.OperationTimeout); } else { throw new ArgumentNullException($"{nameof(ServiceBusConnection)} doesn't have a valid token provider"); } MessagingEventSource.Log.SubscriptionClientCreateStop(serviceBusConnection.Endpoint.Authority, topicPath, subscriptionName, this.ClientId); }
async Task MessageDispatchTask(Message message) { CancellationTokenSource renewLockCancellationTokenSource = null; Timer autoRenewLockCancellationTimer = null; MessagingEventSource.Log.MessageReceiverPumpDispatchTaskStart(this.messageReceiver.ClientId, message); if (this.ShouldRenewLock()) { renewLockCancellationTokenSource = new CancellationTokenSource(); TaskExtensionHelper.Schedule(() => this.RenewMessageLockTask(message, renewLockCancellationTokenSource.Token)); // After a threshold time of renewal('AutoRenewTimeout'), create timer to cancel anymore renewals. autoRenewLockCancellationTimer = new Timer(this.CancelAutoRenewLock, renewLockCancellationTokenSource, this.registerHandlerOptions.MaxAutoRenewDuration, TimeSpan.FromMilliseconds(-1)); } try { MessagingEventSource.Log.MessageReceiverPumpUserCallbackStart(this.messageReceiver.ClientId, message); await this.onMessageCallback(message, this.pumpCancellationToken).ConfigureAwait(false); MessagingEventSource.Log.MessageReceiverPumpUserCallbackStop(this.messageReceiver.ClientId, message); } catch (Exception exception) { MessagingEventSource.Log.MessageReceiverPumpUserCallbackException(this.messageReceiver.ClientId, message, exception); await this.RaiseExceptionReceived(exception, ExceptionReceivedEventArgsAction.UserCallback).ConfigureAwait(false); // Nothing much to do if UserCallback throws, Abandon message and Release semaphore. if (!(exception is MessageLockLostException)) { await this.AbandonMessageIfNeededAsync(message).ConfigureAwait(false); } if (ServiceBusDiagnosticSource.IsEnabled()) { this.diagnosticSource.ReportException(exception); } // AbandonMessageIfNeededAsync should take care of not throwing exception this.maxConcurrentCallsSemaphoreSlim.Release(); return; } finally { renewLockCancellationTokenSource?.Cancel(); renewLockCancellationTokenSource?.Dispose(); autoRenewLockCancellationTimer?.Dispose(); } // If we've made it this far, user callback completed fine. Complete message and Release semaphore. await this.CompleteMessageIfNeededAsync(message).ConfigureAwait(false); this.maxConcurrentCallsSemaphoreSlim.Release(); MessagingEventSource.Log.MessageReceiverPumpDispatchTaskStop(this.messageReceiver.ClientId, message, this.maxConcurrentCallsSemaphoreSlim.CurrentCount); }
public MessageSession( string entityPath, MessagingEntityType?entityType, ReceiveMode receiveMode, ServiceBusConnection serviceBusConnection, ICbsTokenProvider cbsTokenProvider, RetryPolicy retryPolicy, int prefetchCount = Constants.DefaultClientPrefetchCount, string sessionId = null, bool isSessionReceiver = false) : base(entityPath, entityType, receiveMode, serviceBusConnection, cbsTokenProvider, retryPolicy, prefetchCount, sessionId, isSessionReceiver) { this.diagnosticSource = new ServiceBusDiagnosticSource(entityPath, serviceBusConnection.Endpoint); }
public MessageReceivePump(IMessageReceiver messageReceiver, MessageHandlerOptions registerHandlerOptions, Func <Message, CancellationToken, Task> callback, Uri endpoint, CancellationToken pumpCancellationToken) { this.messageReceiver = messageReceiver ?? throw new ArgumentNullException(nameof(messageReceiver)); this.registerHandlerOptions = registerHandlerOptions; this.onMessageCallback = callback; this.endpoint = endpoint.Authority; this.pumpCancellationToken = pumpCancellationToken; this.maxConcurrentCallsSemaphoreSlim = new SemaphoreSlim(this.registerHandlerOptions.MaxConcurrentCalls); this.diagnosticSource = new ServiceBusDiagnosticSource(messageReceiver.Path, endpoint); }
SubscriptionClient(ServiceBusNamespaceConnection serviceBusConnection, string topicPath, string subscriptionName, ReceiveMode receiveMode, RetryPolicy retryPolicy) : base(nameof(SubscriptionClient), $"{topicPath}/{subscriptionName}", retryPolicy) { MessagingEventSource.Log.SubscriptionClientCreateStart(serviceBusConnection?.Endpoint.Authority, topicPath, subscriptionName, receiveMode.ToString()); this.ServiceBusConnection = serviceBusConnection ?? throw new ArgumentNullException(nameof(serviceBusConnection)); this.syncLock = new object(); this.TopicPath = topicPath; this.SubscriptionName = subscriptionName; this.Path = EntityNameHelper.FormatSubscriptionPath(this.TopicPath, this.SubscriptionName); this.ReceiveMode = receiveMode; this.diagnosticSource = new ServiceBusDiagnosticSource(this.Path, serviceBusConnection.Endpoint); MessagingEventSource.Log.SubscriptionClientCreateStop(serviceBusConnection.Endpoint.Authority, topicPath, subscriptionName, this.ClientId); }
internal SessionClient( string clientTypeName, string entityPath, MessagingEntityType?entityType, ReceiveMode receiveMode, int prefetchCount, ServiceBusConnection serviceBusConnection, ICbsTokenProvider cbsTokenProvider, RetryPolicy retryPolicy, IList <ServiceBusPlugin> registeredPlugins) : base(clientTypeName, entityPath, retryPolicy ?? RetryPolicy.Default) { if (string.IsNullOrWhiteSpace(entityPath)) { throw Fx.Exception.ArgumentNullOrWhiteSpace(entityPath); } this.ServiceBusConnection = serviceBusConnection ?? throw new ArgumentNullException(nameof(serviceBusConnection)); this.EntityPath = entityPath; this.EntityType = entityType; this.ReceiveMode = receiveMode; this.PrefetchCount = prefetchCount; this.ServiceBusConnection.ThrowIfClosed(); if (cbsTokenProvider != null) { this.CbsTokenProvider = cbsTokenProvider; } else if (this.ServiceBusConnection.TokenProvider != null) { this.CbsTokenProvider = new TokenProviderAdapter(this.ServiceBusConnection.TokenProvider, this.ServiceBusConnection.OperationTimeout); } else { throw new ArgumentNullException($"{nameof(ServiceBusConnection)} doesn't have a valid token provider"); } this.diagnosticSource = new ServiceBusDiagnosticSource(entityPath, serviceBusConnection.Endpoint); // Register plugins on the message session. if (registeredPlugins != null) { foreach (var serviceBusPlugin in registeredPlugins) { this.RegisterPlugin(serviceBusPlugin); } } }
async Task MessagePumpTaskAsync() { while (!this.pumpCancellationToken.IsCancellationRequested) { Message message = null; try { await this.maxConcurrentCallsSemaphoreSlim.WaitAsync(this.pumpCancellationToken).ConfigureAwait(false); message = await this.messageReceiver.ReceiveAsync(this.registerHandlerOptions.ReceiveTimeOut).ConfigureAwait(false); if (message != null) { MessagingEventSource.Log.MessageReceiverPumpTaskStart(this.messageReceiver.ClientId, message, this.maxConcurrentCallsSemaphoreSlim.CurrentCount); TaskExtensionHelper.Schedule(() => { if (ServiceBusDiagnosticSource.IsEnabled()) { return(this.MessageDispatchTaskInstrumented(message)); } else { return(this.MessageDispatchTask(message)); } }); } } catch (Exception exception) { // Not reporting an ObjectDisposedException as we're stopping the pump if (!(exception is ObjectDisposedException && this.pumpCancellationToken.IsCancellationRequested)) { MessagingEventSource.Log.MessageReceivePumpTaskException(this.messageReceiver.ClientId, string.Empty, exception); await this.RaiseExceptionReceived(exception, ExceptionReceivedEventArgsAction.Receive).ConfigureAwait(false); } } finally { // Either an exception or for some reason message was null, release semaphore and retry. if (message == null) { this.maxConcurrentCallsSemaphoreSlim.Release(); MessagingEventSource.Log.MessageReceiverPumpTaskStop(this.messageReceiver.ClientId, this.maxConcurrentCallsSemaphoreSlim.CurrentCount); } } } }
public SessionReceivePump(string clientId, ISessionClient client, ReceiveMode receiveMode, SessionHandlerOptions sessionHandlerOptions, Func <IMessageSession, Message, CancellationToken, Task> callback, Uri endpoint, CancellationToken token) { this.client = client ?? throw new ArgumentException(nameof(client)); this.clientId = clientId; this.ReceiveMode = receiveMode; this.sessionHandlerOptions = sessionHandlerOptions; this.userOnSessionCallback = callback; this.endpoint = endpoint.Authority; this.entityPath = client.EntityPath; this.pumpCancellationToken = token; this.maxConcurrentSessionsSemaphoreSlim = new SemaphoreSlim(this.sessionHandlerOptions.MaxConcurrentSessions); this.maxPendingAcceptSessionsSemaphoreSlim = new SemaphoreSlim(this.sessionHandlerOptions.MaxConcurrentAcceptSessionCalls); this.diagnosticSource = new ServiceBusDiagnosticSource(client.EntityPath, endpoint); }
async Task MessagePumpTaskAsync(IMessageSession session) { if (session == null) { return; } var renewLockCancellationTokenSource = new CancellationTokenSource(); if (this.ShouldRenewSessionLock()) { TaskExtensionHelper.Schedule(() => this.RenewSessionLockTaskAsync(session, renewLockCancellationTokenSource.Token)); } var autoRenewLockCancellationTimer = new Timer( CancelAutoRenewLock, renewLockCancellationTokenSource, Timeout.Infinite, Timeout.Infinite); try { while (!this.pumpCancellationToken.IsCancellationRequested && !session.IsClosedOrClosing) { Message message; try { message = await session.ReceiveAsync(this.sessionHandlerOptions.MessageWaitTimeout).ConfigureAwait(false); } catch (Exception exception) { MessagingEventSource.Log.MessageReceivePumpTaskException(this.clientId, session.SessionId, exception); if (exception is ServiceBusTimeoutException) { // Timeout Exceptions are pretty common. Not alerting the User on this. continue; } if (!(exception is ObjectDisposedException && this.pumpCancellationToken.IsCancellationRequested)) { await this.RaiseExceptionReceived(exception, ExceptionReceivedEventArgsAction.Receive).ConfigureAwait(false); } break; } if (message == null) { MessagingEventSource.Log.SessionReceivePumpSessionEmpty(this.clientId, session.SessionId); break; } bool isDiagnosticSourceEnabled = ServiceBusDiagnosticSource.IsEnabled(); Activity activity = isDiagnosticSourceEnabled ? this.diagnosticSource.ProcessSessionStart(session, message) : null; Task processTask = null; try { // Set the timer autoRenewLockCancellationTimer.Change(this.sessionHandlerOptions.MaxAutoRenewDuration, TimeSpan.FromMilliseconds(-1)); var callbackExceptionOccurred = false; try { processTask = this.userOnSessionCallback(session, message, this.pumpCancellationToken); await processTask.ConfigureAwait(false); } catch (Exception exception) { if (isDiagnosticSourceEnabled) { this.diagnosticSource.ReportException(exception); } MessagingEventSource.Log.MessageReceivePumpTaskException(this.clientId, session.SessionId, exception); await this.RaiseExceptionReceived(exception, ExceptionReceivedEventArgsAction.UserCallback).ConfigureAwait(false); callbackExceptionOccurred = true; if (!(exception is MessageLockLostException || exception is SessionLockLostException)) { await this.AbandonMessageIfNeededAsync(session, message).ConfigureAwait(false); } } finally { autoRenewLockCancellationTimer.Change(Timeout.Infinite, Timeout.Infinite); } if (!callbackExceptionOccurred) { await this.CompleteMessageIfNeededAsync(session, message).ConfigureAwait(false); } else if (session.IsClosedOrClosing) { // If User closed the session as part of the callback, break out of the loop break; } } finally { this.diagnosticSource.ProcessSessionStop(activity, session, message, processTask?.Status); } } } finally { renewLockCancellationTokenSource.Cancel(); renewLockCancellationTokenSource.Dispose(); autoRenewLockCancellationTimer.Dispose(); await this.CloseSessionIfNeededAsync(session).ConfigureAwait(false); this.maxConcurrentSessionsSemaphoreSlim.Release(); } }