Example #1
0
        public void ReleaseLock(LockTicket ticket)
        {
            if (ticket == null)
            {
                throw new ArgumentNullException(nameof(ticket));
            }

            // Get the lock client for the granted request, release the lock, and dispose the client.
            if (_lockClients.TryRemove(ticket.RequestId, out LockServiceClient lockClient))
            {
                LogDebug($"Releasing lock for {ticket.ResourceId}.");
                try
                {
                    lockClient.ReleaseLock();
                }
                catch (Exception ex)
                {
                    LogError($"Unable to send release request to lock service.", ex);
                }
                finally
                {
                    // Must ensure the client is disposed even if the release request fails.
                    // Otherwise the client will keep responding to the ping requests from the lock service
                    // and the lock might never get cleaned up.
                    lockClient.Dispose();
                }
            }
        }
Example #2
0
        /// <summary>
        /// Selects a <see cref="LockToken" /> from the provided list, based on current
        /// availability of the associated resources, then obtains an exlusive lock
        /// and executes the specified <see cref="Action{LockToken}" /> before releasing the lock.
        /// </summary>
        /// <param name="tokens">The collection of tokens to choose from.</param>
        /// <param name="action">The action to execute; takes the acquired token as a parameter.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="tokens" /> is null.
        /// <para>or</para>
        /// <paramref name="action" /> is null.
        /// </exception>
        /// <exception cref="ArgumentException"><paramref name="tokens" /> contains no elements.</exception>
        /// <exception cref="AcquireLockTimeoutException">The lock could not be obtained within the acquisition timeout specified by the selected token.</exception>
        /// <exception cref="HoldLockTimeoutException"><paramref name="action" /> did not complete within the hold timeout specified by the selected token.</exception>
        public void Run(IEnumerable <LockToken> tokens, Action <LockToken> action)
        {
            if (tokens == null)
            {
                throw new ArgumentNullException(nameof(tokens));
            }

            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            if (!tokens.Any())
            {
                throw new ArgumentException("No lock tokens were specified.", nameof(tokens));
            }

            // Send the lock tokens in a random order to prevent picking the same one every time if they are all available
            Random random = new Random();
            IEnumerable <string> tokenIds   = tokens.Select(n => n.Key).OrderBy(n => random.Next());
            LockTicket           lockTicket = _lockManager.AcquireLock(tokenIds, tokens.First().AcquireTimeout, 1, _requestName);

            try
            {
                LockToken acquiredToken = tokens.First(n => n.Key == lockTicket.ResourceId);
                RunAction(acquiredToken, () => action(acquiredToken));
            }
            finally
            {
                _lockManager.ReleaseLock(lockTicket);
            }
        }
Example #3
0
        /// <summary>
        /// Releases the lock specified by the <see cref="LockTicket" />.
        /// </summary>
        /// <param name="ticket">The <see cref="LockTicket" /> identifying the lock to release.</param>
        /// <exception cref="ArgumentNullException"><paramref name="ticket" /> is null.</exception>
        public void ReleaseLock(LockTicket ticket)
        {
            if (ticket == null)
            {
                throw new ArgumentNullException(nameof(ticket));
            }

            ReleaseLock(ticket.RequestId);
        }
Example #4
0
 /// <summary>
 /// Signals the client that the lock request has been granted.
 /// </summary>
 /// <param name="resourceId">The identifier for the locked resource.</param>
 public void GrantLock(string resourceId)
 {
     LogTrace($"Received lock grant signal for {resourceId}.");
     try
     {
         LockTicket = new LockTicket(_requestId, resourceId);
         _waitEvent.Set();
     }
     catch (ObjectDisposedException)
     {
         // Race condition - ignore.
     }
 }
Example #5
0
        private LockTicket AcquireLock(Action <LockServiceClient> requestAction, TimeSpan waitTime, string requestName)
        {
            // Create a new LockServiceClient, then request the lock and wait for a response.
            LockServiceClient lockClient = new LockServiceClient(_lockServiceAddress, requestName);

            try
            {
                requestAction(lockClient);
            }
            catch (Exception ex)
            {
                // It is crucial to dispose the lock client here to avoid any lingering callback hosts
                LogError($"Unable to send acquire request to lock service.", ex);
                lockClient.Dispose();
                throw;
            }

            LogDebug("Lock requested, waiting for grant.");
            LockTicket ticket = lockClient.WaitForLockGranted(waitTime);

            if (ticket != null)
            {
                // Request was granted - persist the lock client for this request so that the service
                // can ping it periodically to make sure it is still alive.
                LogDebug($"Acquired lock for {ticket.ResourceId}.");
                _lockClients.TryAdd(ticket.RequestId, lockClient);
                return(ticket);
            }
            else
            {
                // Did not get the lock in time.  Cancel the request on the server and dispose the client.
                LogDebug($"Unable to acquire lock within {waitTime}.  Canceling request.");
                try
                {
                    lockClient.CancelRequest();
                }
                catch (Exception ex)
                {
                    LogError($"Unable to send cancel request to lock service.", ex);
                }
                finally
                {
                    // Must ensure the client is disposed even if the cancel request fails.
                    lockClient.Dispose();
                }
                throw new AcquireLockTimeoutException($"Unable to acquire lock within {waitTime}.");
            }
        }
Example #6
0
        /// <summary>
        /// Obtains an exclusive lock according to the specified <see cref="LockToken" />,
        /// then executes the specified <see cref="Action" /> before releasing the lock.
        /// </summary>
        /// <param name="token">The token dictating the scope and behavior of execution.</param>
        /// <param name="action">The action to execute.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="token" /> is null.
        /// <para>or</para>
        /// <paramref name="action" /> is null.
        /// </exception>
        /// <exception cref="AcquireLockTimeoutException">The lock could not be obtained within the acquisition timeout specified by <paramref name="token" />.</exception>
        /// <exception cref="HoldLockTimeoutException"><paramref name="action" /> did not complete within the hold timeout specified by <paramref name="token" />.</exception>
        public void Run(LockToken token, Action action)
        {
            if (token == null)
            {
                throw new ArgumentNullException(nameof(token));
            }

            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            LockTicket lockTicket = _lockManager.AcquireLock(token.Key, token.AcquireTimeout, 1, _requestName);

            try
            {
                RunAction(token, action);
            }
            finally
            {
                _lockManager.ReleaseLock(lockTicket);
            }
        }