/// <summary>
        /// Set a custom state on the session which can be later retrieved using <see cref="GetSessionStateAsync"/>
        /// </summary>
        ///
        /// <param name="sessionState">A <see cref="BinaryData"/> of session state</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        /// <remarks>This state is stored on Service Bus forever unless you set an empty state on it.</remarks>
        ///
        /// <returns>A task to be resolved on when the operation has completed.</returns>
        public virtual async Task SetSessionStateAsync(
            BinaryData sessionState,
            CancellationToken cancellationToken = default)
        {
            Argument.AssertNotDisposed(IsClosed, nameof(ServiceBusSessionReceiver));
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            Logger.SetSessionStateStart(Identifier, SessionId);
            using DiagnosticScope scope = ScopeFactory.CreateScope(
                      DiagnosticProperty.SetSessionStateActivityName,
                      sessionId: SessionId);
            scope.Start();

            try
            {
                await InnerReceiver.SetStateAsync(sessionState, cancellationToken).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                Logger.SetSessionStateException(Identifier, exception.ToString());
                scope.Failed(exception);
                throw;
            }

            Logger.SetSessionStateComplete(Identifier);
        }
예제 #2
0
        /// <summary>
        /// Renews the lock on the message. The lock will be renewed based on the setting specified on the queue.
        /// </summary>
        ///
        /// <remarks>
        /// When a message is received in <see cref="ReceiveMode.PeekLock"/> mode, the message is locked on the server for this
        /// receiver instance for a duration as specified during the Queue/Subscription creation (LockDuration).
        /// If processing of the message requires longer than this duration, the lock needs to be renewed.
        /// For each renewal, it resets the time the message is locked by the LockDuration set on the Entity.
        /// </remarks>
        ///
        /// <param name="lockToken">The lockToken of the <see cref="ServiceBusReceivedMessage"/> to renew the lock for.</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        public virtual async Task <DateTimeOffset> RenewMessageLockAsync(
            string lockToken,
            CancellationToken cancellationToken = default)
        {
            ThrowIfLockTokenIsEmpty(lockToken);
            Argument.AssertNotClosed(IsDisposed, nameof(ServiceBusReceiver));
            ThrowIfNotPeekLockMode();
            ThrowIfSessionReceiver();
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            Logger.RenewMessageLockStart(Identifier, 1, lockToken);
            using DiagnosticScope scope = ScopeFactory.CreateScope(
                      DiagnosticProperty.RenewMessageLockActivityName,
                      lockToken: lockToken);
            scope.Start();

            DateTimeOffset lockedUntil;

            try
            {
                lockedUntil = await InnerReceiver.RenewMessageLockAsync(
                    lockToken,
                    cancellationToken).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                Logger.RenewMessageLockException(Identifier, exception.ToString());
                scope.Failed(exception);
                throw;
            }

            Logger.RenewMessageLockComplete(Identifier);
            scope.AddAttribute(DiagnosticProperty.LockedUntilAttribute, lockedUntil);
            return(lockedUntil);
        }
예제 #3
0
        /// <summary> Indicates that the receiver wants to defer the processing for the message.</summary>
        ///
        /// <param name="lockToken">The lockToken of the <see cref="ServiceBusReceivedMessage"/> to defer.</param>
        /// <param name="propertiesToModify">The properties of the message to modify while deferring the message.</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        /// <remarks>
        /// A lock token can be found in <see cref="ServiceBusReceivedMessage.LockToken"/>,
        /// only when <see cref="ReceiveMode"/> is set to <see cref="ReceiveMode.PeekLock"/>.
        /// In order to receive this message again in the future, you will need to save the
        /// <see cref="ServiceBusReceivedMessage.SequenceNumber"/>
        /// and receive it using <see cref="ReceiveDeferredMessageAsync(long, CancellationToken)"/>.
        /// Deferring messages does not impact message's expiration, meaning that deferred messages can still expire.
        /// This operation can only be performed on messages that were received by this receiver.
        /// </remarks>
        ///
        /// <returns>A task to be resolved on when the operation has completed.</returns>
        public virtual async Task DeferMessageAsync(
            string lockToken,
            IDictionary <string, object> propertiesToModify = null,
            CancellationToken cancellationToken             = default)
        {
            ThrowIfLockTokenIsEmpty(lockToken);
            Argument.AssertNotClosed(IsDisposed, nameof(ServiceBusReceiver));
            ThrowIfNotPeekLockMode();
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            Logger.DeferMessageStart(Identifier, 1, lockToken);
            using DiagnosticScope scope = ScopeFactory.CreateScope(
                      DiagnosticProperty.DeferActivityName,
                      lockToken: lockToken);
            scope.Start();

            try
            {
                await InnerReceiver.DeferAsync(
                    lockToken,
                    propertiesToModify,
                    cancellationToken).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                Logger.DeferMessageException(Identifier, exception.ToString());
                scope.Failed(exception);
                throw;
            }

            Logger.DeferMessageComplete(Identifier);
        }
예제 #4
0
        /// <summary>
        /// Receives a <see cref="IList{ServiceBusReceivedMessage}"/> of deferred messages identified by <paramref name="sequenceNumbers"/>.
        /// </summary>
        ///
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        /// <param name="sequenceNumbers">An <see cref="IEnumerable{T}"/> containing the sequence numbers to receive.</param>
        ///
        /// <returns>Messages identified by sequence number are returned. Returns null if no messages are found.
        /// Throws if the messages have not been deferred.</returns>
        /// <seealso cref="DeferMessageAsync(ServiceBusReceivedMessage, IDictionary{string, object}, CancellationToken)"/>
        /// <seealso cref="DeferMessageAsync(string, IDictionary{string, object}, CancellationToken)"/>
        public virtual async Task <IList <ServiceBusReceivedMessage> > ReceiveDeferredMessagesAsync(
            IEnumerable <long> sequenceNumbers,
            CancellationToken cancellationToken = default)
        {
            Argument.AssertNotClosed(IsDisposed, nameof(ServiceBusReceiver));
            Argument.AssertNotNullOrEmpty(sequenceNumbers, nameof(sequenceNumbers));
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            var sequenceNumbersList = sequenceNumbers.ToList();

            Logger.ReceiveDeferredMessageStart(Identifier, sequenceNumbersList);
            using DiagnosticScope scope = ScopeFactory.CreateScope(DiagnosticProperty.ReceiveDeferredActivityName);
            scope.AddAttribute(
                DiagnosticProperty.SequenceNumbersAttribute,
                string.Join(",", sequenceNumbers));
            scope.Start();

            IList <ServiceBusReceivedMessage> deferredMessages = null;

            try
            {
                deferredMessages = await InnerReceiver.ReceiveDeferredMessagesAsync(
                    sequenceNumbersList,
                    cancellationToken).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                Logger.ReceiveDeferredMessageException(Identifier, exception.ToString());
                scope.Failed(exception);
                throw;
            }

            Logger.ReceiveDeferredMessageComplete(Identifier, deferredMessages.Count);
            scope.SetMessageData(deferredMessages);
            return(deferredMessages);
        }
예제 #5
0
        /// <summary>
        /// Fetches a list of active messages without changing the state of the receiver or the message source.
        /// </summary>
        /// <param name="sequenceNumber">The sequence number from where to peek the message.</param>
        /// <param name="maxMessages">The maximum number of messages that will be fetched.</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        /// <returns>An <see cref="IList{ServiceBusReceivedMessage}" /> of messages that were peeked.</returns>
        private async Task <IList <ServiceBusReceivedMessage> > PeekMessagesInternalAsync(
            long?sequenceNumber,
            int maxMessages,
            CancellationToken cancellationToken)
        {
            Argument.AssertNotClosed(IsDisposed, nameof(ServiceBusReceiver));
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            Logger.PeekMessageStart(Identifier, sequenceNumber, maxMessages);
            using DiagnosticScope scope = ScopeFactory.CreateScope(
                      DiagnosticProperty.PeekActivityName,
                      requestedMessageCount: maxMessages);
            scope.Start();

            IList <ServiceBusReceivedMessage> messages = new List <ServiceBusReceivedMessage>();

            try
            {
                messages = await InnerReceiver.PeekMessagesAsync(
                    sequenceNumber,
                    maxMessages,
                    cancellationToken)
                           .ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                Logger.PeekMessageException(Identifier, exception.ToString());
                scope.Failed(exception);
                throw;
            }

            Logger.PeekMessageComplete(Identifier, messages.Count);
            scope.SetMessageData(messages);
            return(messages);
        }
예제 #6
0
        public virtual async ValueTask DisposeAsync()
        {
            IsDisposed = true;
            Type clientType = GetType();

            Logger.ClientDisposeStart(clientType, Identifier);
            try
            {
                await InnerReceiver.CloseAsync(CancellationToken.None).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                Logger.ClientDisposeException(clientType, Identifier, ex);
                throw;
            }

            Logger.ClientDisposeComplete(clientType, Identifier);
        }
예제 #7
0
        /// <summary>
        /// Renews the lock on the session specified by the <see cref="SessionId"/>. The lock will be renewed based on the setting specified on the entity.
        /// </summary>
        ///
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        /// <remarks>
        /// <para>
        /// When you get session receiver, the session is locked for this receiver by the service for a duration as specified during the Queue/Subscription creation.
        /// If processing of the session requires longer than this duration, the session-lock needs to be renewed.
        /// For each renewal, it resets the time the session is locked by the LockDuration set on the Entity.
        /// </para>
        /// <para>
        /// Renewal of session renews all the messages in the session as well. Each individual message need not be renewed.
        /// </para>
        /// </remarks>
        public virtual async Task RenewSessionLockAsync(CancellationToken cancellationToken = default)
        {
            Argument.AssertNotClosed(IsDisposed, nameof(ServiceBusSessionReceiver));
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            ServiceBusEventSource.Log.RenewSessionLockStart(Identifier, SessionId);

            try
            {
                await InnerReceiver.RenewSessionLockAsync(cancellationToken).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                ServiceBusEventSource.Log.RenewSessionLockException(Identifier, exception);
                throw;
            }

            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            ServiceBusEventSource.Log.RenewSessionLockComplete(Identifier);
        }
예제 #8
0
        /// <summary>
        /// Receives a list of <see cref="ServiceBusReceivedMessage" /> from the entity using <see cref="ReceiveMode"/> mode.
        /// <see cref="ReceiveMode"/> defaults to PeekLock mode.
        /// This method doesn't guarantee to return exact `maxMessages` messages,
        /// even if there are `maxMessages` messages available in the queue or topic.
        /// </summary>
        ///
        /// <param name="maxMessages">The maximum number of messages that will be received.</param>
        /// <param name="maxWaitTime">An optional <see cref="TimeSpan"/> specifying the maximum time to wait for the first message before returning an empty list if no messages are available.
        /// If not specified, the <see cref="ServiceBusRetryOptions.TryTimeout"/> will be used.</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        /// <returns>List of messages received. Returns an empty list if no message is found.</returns>
        public virtual async Task <IList <ServiceBusReceivedMessage> > ReceiveMessagesAsync(
            int maxMessages,
            TimeSpan?maxWaitTime = default,
            CancellationToken cancellationToken = default)
        {
            Argument.AssertAtLeast(maxMessages, 1, nameof(maxMessages));
            Argument.AssertNotClosed(IsDisposed, nameof(ServiceBusReceiver));
            if (maxWaitTime.HasValue)
            {
                Argument.AssertPositive(maxWaitTime.Value, nameof(maxWaitTime));
            }

            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            Logger.ReceiveMessageStart(Identifier, maxMessages);
            using DiagnosticScope scope = ScopeFactory.CreateScope(
                      DiagnosticProperty.ReceiveActivityName,
                      requestedMessageCount: maxMessages);
            scope.Start();

            IList <ServiceBusReceivedMessage> messages = null;

            try
            {
                messages = await InnerReceiver.ReceiveMessagesAsync(
                    maxMessages,
                    maxWaitTime,
                    cancellationToken).ConfigureAwait(false);
                await ApplyPlugins(messages).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                Logger.ReceiveMessageException(Identifier, exception.ToString());
                scope.Failed(exception);
                throw;
            }

            Logger.ReceiveMessageComplete(Identifier, messages.Count);
            scope.SetMessageData(messages);

            return(messages);
        }
예제 #9
0
        /// <summary>
        /// Gets the session state.
        /// </summary>
        ///
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        /// <returns>The session state as byte array.</returns>
        public virtual async Task <byte[]> GetStateAsync(CancellationToken cancellationToken = default)
        {
            Argument.AssertNotClosed(IsDisposed, nameof(ServiceBusSessionReceiver));
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            ServiceBusEventSource.Log.GetSessionStateStart(Identifier, SessionId);
            byte[] sessionState = null;

            try
            {
                sessionState = await InnerReceiver.GetStateAsync(cancellationToken).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                ServiceBusEventSource.Log.GetSessionStateException(Identifier, exception);
                throw;
            }

            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            ServiceBusEventSource.Log.GetSessionStateComplete(Identifier);
            return(sessionState);
        }
예제 #10
0
        /// <summary>
        /// Set a custom state on the session which can be later retrieved using <see cref="GetSessionStateAsync"/>
        /// </summary>
        ///
        /// <param name="sessionState">A byte array of session state</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        /// <remarks>This state is stored on Service Bus forever unless you set an empty state on it.</remarks>
        ///
        /// <returns>A task to be resolved on when the operation has completed.</returns>
        public virtual async Task SetSessionStateAsync(
            byte[] sessionState,
            CancellationToken cancellationToken = default)
        {
            Argument.AssertNotClosed(IsDisposed, nameof(ServiceBusSessionReceiver));
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            Logger.SetSessionStateStart(Identifier, SessionId);

            try
            {
                await InnerReceiver.SetStateAsync(sessionState, cancellationToken).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                Logger.SetSessionStateException(Identifier, exception.ToString());
                throw;
            }

            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            Logger.SetSessionStateComplete(Identifier);
        }
예제 #11
0
        /// <summary>
        /// Renews the lock on the session specified by the <see cref="SessionId"/>. The lock will be renewed based on the setting specified on the entity.
        /// </summary>
        ///
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        /// <remarks>
        /// <para>
        /// When you accept a session, the session is locked for this receiver by the service for a duration as specified during the Queue/Subscription creation.
        /// If processing of the session requires longer than this duration, the session-lock needs to be renewed.
        /// For each renewal, it resets the time the session is locked by the LockDuration set on the Entity.
        /// </para>
        /// <para>
        /// Renewal of session renews all the messages in the session as well. Each individual message need not be renewed.
        /// </para>
        /// </remarks>
        /// <exception cref="ServiceBusException">
        ///   The lock for the session has expired.
        ///   The <see cref="ServiceBusException.Reason" /> will be set to <see cref="ServiceBusFailureReason.SessionLockLost"/> in this case.
        /// </exception>
        public virtual async Task RenewSessionLockAsync(CancellationToken cancellationToken = default)
        {
            Argument.AssertNotDisposed(IsClosed, nameof(ServiceBusSessionReceiver));
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            Logger.RenewSessionLockStart(Identifier, SessionId);
            using DiagnosticScope scope = ScopeFactory.CreateScope(
                      DiagnosticProperty.RenewSessionLockActivityName,
                      DiagnosticScope.ActivityKind.Client);
            scope.Start();

            try
            {
                await InnerReceiver.RenewSessionLockAsync(cancellationToken).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                Logger.RenewSessionLockException(Identifier, exception.ToString());
                scope.Failed(exception);
                throw;
            }

            Logger.RenewSessionLockComplete(Identifier);
        }
예제 #12
0
 /// <summary>
 /// Opens an AMQP link for use with receiver operations.
 /// </summary>
 ///
 /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
 ///
 /// <returns>A task to be resolved on when the operation has completed.</returns>
 internal async Task OpenLinkAsync(CancellationToken cancellationToken) =>
 await InnerReceiver.OpenLinkAsync(cancellationToken).ConfigureAwait(false);