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);
                }
            }
        }
Example #2
0
        /// <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);
        }
Example #4
0
 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);
        }
Example #7
0
        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);
                    }
                }
            }
        }
Example #9
0
 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);
 }
Example #10
0
        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();
            }
        }