Beispiel #1
0
        public async Task CloudLock_ShouldRelease_WhenDisposed()
        {
            using (var cloudLock = new CloudLock(blob, CloudLock.MinimumAcquireTimeSpan))
            {
                Assert.IsTrue(await cloudLock.AcquireAsync(5, TimeSpan.FromSeconds(1)));
            }

            //Lock should be acquired
            var acquiredLeaseId = await blob.AcquireLeaseAsync(CloudLock.MinimumAcquireTimeSpan, null);

            Assert.IsNotNull(acquiredLeaseId);
            await blob.ReleaseLeaseAsync(AccessCondition.GenerateLeaseCondition(acquiredLeaseId));
        }
Beispiel #2
0
        private static async Task <string> TryAcquireLeaseAsync(
            CloudBlockBlob blob,
            TimeSpan leasePeriod,
            CancellationToken cancellationToken)
        {
            try
            {
                // Optimistically try to acquire the lease. The blob may not yet
                // exist. If it doesn't we handle the 404, create it, and retry below
                return(await blob.AcquireLeaseAsync(leasePeriod).ConfigureAwait(false));
            }
            catch (StorageException exception)
            {
                if (exception.RequestInformation != null)
                {
                    switch (exception.RequestInformation.HttpStatusCode)
                    {
                    case 409:
                        return(null);

                    case 404:
                        break;

                    default:
                        throw;
                    }
                }
                else
                {
                    throw;
                }
            }

            //404
            await TryCreateAsync(blob, cancellationToken).ConfigureAwait(false);

            try
            {
                return(await blob.AcquireLeaseAsync(leasePeriod).ConfigureAwait(false));
            }
            catch (StorageException exception)
            {
                if (exception.RequestInformation != null &&
                    exception.RequestInformation.HttpStatusCode == 409)
                {
                    return(null);
                }

                throw;
            }
        }
Beispiel #3
0
        public async Task <IFileInformation> CopyFileToSameServiceType(string identifier, IStorageService destinationService)
        {
            var destination = (AzureStorageService)destinationService;

            var            uniqueName = Guid.NewGuid().ToString();
            CloudBlockBlob sourceBlob = null;

            try
            {
                sourceBlob = BlobContainer.GetBlockBlobReference(identifier);
                await sourceBlob.AcquireLeaseAsync(null);

                var destinationBlob = destination.BlobContainer.GetBlockBlobReference(uniqueName);
                await destinationBlob.StartCopyAsync(sourceBlob);
            }
            finally
            {
                // Break the lease on the source blob.
                if (sourceBlob != null)
                {
                    await sourceBlob.FetchAttributesAsync();

                    if (sourceBlob.Properties.LeaseState != LeaseState.Available)
                    {
                        await sourceBlob.BreakLeaseAsync(new TimeSpan(0));
                    }
                }
            }

            var info = new AzureFileInformation {
                StorageIdentifier = uniqueName
            };

            return(info);
        }
Beispiel #4
0
        public async Task <bool> TryGetLease(ILogger logger)
        {
            try
            {
                // first, try to get the lease
                LeaseId = await stateBlob.AcquireLeaseAsync(TimeSpan.FromSeconds(15), null);

                // start a background lease renewal process
                ignoredTask = Task.Run(LeaseRenewalLoop);

                return(true);
            }
            catch (StorageException ex)
            {
                var information = ex.RequestInformation.ExtendedErrorInformation;
                if (information != null && information.ErrorCode == "LeaseAlreadyPresent")
                {
                    return(false);
                }
                if ((ex.RequestInformation.HttpStatusCode == 404) && (information.ErrorCode.Equals(BlobErrorCodeStrings.ContainerNotFound)))
                {
                    logger.LogWarning("Invalid application state (Container not found). Ignoring Doorbell. Did you forget to initialize the service?");
                    return(false);
                }
                if ((ex.RequestInformation.HttpStatusCode == 404) && (information.ErrorCode.Equals(BlobErrorCodeStrings.BlobNotFound)))
                {
                    logger.LogWarning("Invalid application state (Blob not found). Ignoring Doorbell. Did you forget to initialize the service?");
                    return(false);
                }

                throw;
            }
        }
Beispiel #5
0
        public async Task <string> CreateLock(string sagaId)
        {
            var sagaIdToGuid = StringToGuid(sagaId);


            // Create a container called
            var cloudBlobContainer = cloudBlobClient.GetContainerReference(CONTAINER_NAME);

            CloudBlockBlob blob = cloudBlobContainer.GetBlockBlobReference(sagaId);

            await blob.UploadTextAsync(sagaId);

            var leaseId = string.Empty;

            try
            {
                leaseId = await blob.AcquireLeaseAsync(LOCK_DURATION);
            }
            catch (StorageException ex)
            {
                Random rnd = new Random();
                await Task.Delay(rnd.Next(MIN_WAITING_FOR_LOCK_RELEASING, MAX_WAITING_FOR_LOCK_RELEASING));

                throw;
            }

            return(leaseId);
        }
        public string AcquireLeaseOnBlob(
            string blob,
            TimeSpan?maxWaitDefault = null,
            TimeSpan?delayDefault   = null)
        {
            TimeSpan maxWait = maxWaitDefault ?? TimeSpan.FromSeconds(120);
            TimeSpan delay   = delayDefault ?? TimeSpan.FromMilliseconds(500);

            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();

            // This will throw an exception with HTTP code 409 when we cannot acquire the lease
            // But we should block until we can get this lease, with a timeout (maxWaitSeconds)
            while (stopWatch.ElapsedMilliseconds < maxWait.TotalMilliseconds)
            {
                try
                {
                    CloudBlockBlob cloudBlob = _blobContainer.GetBlockBlobReference(blob);
                    System.Threading.Tasks.Task <string> task = cloudBlob.AcquireLeaseAsync(TimeSpan.FromMinutes(1), null);
                    task.Wait();
                    return(task.Result);
                }
                catch (Exception e)
                {
                    Console.WriteLine($"Retrying lease acquisition on {blob}, {e.Message}");
                    Thread.Sleep(delay);
                }
            }

            throw new Exception($"Unable to acquire lease on {blob}");
        }
Beispiel #7
0
        public async Task <string> TryAcquireLeaseAsync(CloudBlockBlob blob, TimeSpan leasePeriod)
        {
            try
            {
                var id = await blob.AcquireLeaseAsync(leasePeriod, null);

                return(id);
            }
            catch (StorageException exception)
            {
                if (exception.IsConflictLeaseAlreadyPresent())
                {
                    return(null);
                }
                else if (exception.IsNotFoundBlobOrContainerNotFound())
                {
                    // If someone deleted the receipt, there's no lease to acquire.
                    return(null);
                }
                else
                {
                    throw;
                }
            }
        }
Beispiel #8
0
        public async Task RunWithLeaseAsync(Func <ILeasedExecutedMigrationsStorage, Task> action, CancellationToken cancellationToken = default)
        {
            await CreateIfNotExistsAsync(cancellationToken);

            string leaseId = null;

            try
            {
                leaseId = await blob.AcquireLeaseAsync(
                    null,
                    null,
                    AccessCondition.GenerateEmptyCondition(),
                    new BlobRequestOptions(),
                    new OperationContext(),
                    cancellationToken);
            }
            catch (StorageException e)
                when(e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict)
                {
                    throw new InvalidOperationException($"The lease for blob {blob.Uri.AbsolutePath} is already leased.");
                }

            try
            {
                var leasedStorage = new AzureBlobLeasedExecutedMigrationsStorage(blob, leaseId);
                await action(leasedStorage);
            }
            finally
            {
                await blob.ReleaseLeaseAsync(AccessCondition.GenerateLeaseCondition(leaseId));
            }
        }
        public async Task <string> AcquireLeaseAsync(TimeSpan?period, string proposedLeaseId = null)
        {
            await EnsureBlobExistsAsync();

            try
            {
                return(await m_blob.AcquireLeaseAsync(period, proposedLeaseId));
            }
            catch (StorageException exception)
            {
                var blobLeased =
                    exception.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict
                    &&
                    exception.RequestInformation.ExtendedErrorInformation.ErrorCode ==
                    BlobErrorCodeStrings.LeaseAlreadyPresent;

                if (blobLeased)
                {
                    throw new LeaseAlreadyAcquiredException(
                              "Blob lease \"{0}\" already acquired.".FormatString(m_blob.Uri),
                              exception);
                }

                throw;
            }
        }
        public async Task <string> CreateLock(string sagaId)
        {
            var sagaIdToGuid = StringToGuid(sagaId);

            // Create the CloudBlobClient that is used to call the Blob Service for that storage account.
            CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();

            // Create a container called
            var cloudBlobContainer = cloudBlobClient.GetContainerReference(CONTAINER_NAME);

            CloudBlockBlob blob = cloudBlobContainer.GetBlockBlobReference(sagaId);

            await blob.UploadTextAsync(sagaId);

            var leaseId = string.Empty;

            try
            {
                leaseId = await blob.AcquireLeaseAsync(LOCK_DURATION);
            }
            catch (StorageException)
            {
                Random rnd = new Random();
                await Task.Delay(rnd.Next(0, 1000));

                throw;
            }

            return(leaseId);
        }
Beispiel #11
0
        public async Task <bool> AcquireAsync(BlobLease lease, string owner)
        {
            CloudBlockBlob leaseBlob = lease.Blob;

            try
            {
                await leaseBlob.FetchAttributesAsync();

                string newLeaseId = Guid.NewGuid().ToString("N");
                if (leaseBlob.Properties.LeaseState == LeaseState.Leased)
                {
                    lease.Token = await leaseBlob.ChangeLeaseAsync(newLeaseId, accessCondition : AccessCondition.GenerateLeaseCondition(lease.Token));
                }
                else
                {
                    lease.Token = await leaseBlob.AcquireLeaseAsync(this.leaseInterval, newLeaseId);
                }

                this.stats.StorageRequests.Increment();
                lease.Owner = owner;
                // Increment Epoch each time lease is acquired or stolen by new host
                lease.Epoch += 1;
                await leaseBlob.UploadTextAsync(JsonConvert.SerializeObject(lease), null, AccessCondition.GenerateLeaseCondition(lease.Token), null, null);

                this.stats.StorageRequests.Increment();
            }
            catch (StorageException storageException)
            {
                this.stats.StorageRequests.Increment();
                throw HandleStorageException(lease, storageException);
            }

            return(true);
        }
Beispiel #12
0
        private async Task <LeaseResult> TryAcquireAsync(CloudBlockBlob blob, TimeSpan leaseTime, CancellationToken cancellationToken)
        {
            if (leaseTime < MinLeaseTime || leaseTime > MaxLeaseTime)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(leaseTime),
                          "The lease time must be between 15 and 60 seconds, inclusive.");
            }

            try
            {
                var leaseId = await blob.AcquireLeaseAsync(
                    leaseTime : leaseTime,
                    proposedLeaseId : null,
                    accessCondition : null,
                    options : null,
                    operationContext : null,
                    cancellationToken : cancellationToken);

                return(LeaseResult.Success(leaseId));
            }
            catch (StorageException ex) when(ex.RequestInformation?.HttpStatusCode == (int)HttpStatusCode.Conflict)
            {
                // The lease has already been acquired by someone else.
                return(LeaseResult.Failure());
            }
        }
Beispiel #13
0
        public async Task <(bool, string)> GetLockAsync(string key)
        {
            try
            {
                CloudBlockBlob blob = _blobContainer.GetBlockBlobReference(key);
                if (!await blob.ExistsAsync())
                {
                    await blob.UploadTextAsync("lock");
                }
                string leaseId = await blob.AcquireLeaseAsync(TimeSpan.FromSeconds(30));

                lock (_timerCache)
                {
                    if (_timerCache.ContainsKey(key))
                    {
                        _timerCache.Remove(key);
                    }
                    _timerCache.Add(key, new LeaseTimer(blob, leaseId));
                }
                return(true, leaseId);
            }
            // TODO: Don't catch 'em all!
            catch
            {
                return(false, null);
            }
        }
Beispiel #14
0
        public string AcquireLeaseOnBlob(string blob)
        {
            CloudBlockBlob cloudBlob = _blobContainer.GetBlockBlobReference(blob);

            System.Threading.Tasks.Task <string> task = cloudBlob.AcquireLeaseAsync(TimeSpan.FromMinutes(1), null);
            task.Wait();
            return(task.Result);
        }
Beispiel #15
0
        async Task <bool> AcquireLeaseCoreAsync(AzureBlobLease lease)
        {
            CloudBlockBlob leaseBlob   = lease.Blob;
            bool           retval      = true;
            string         newLeaseId  = Guid.NewGuid().ToString();
            string         partitionId = lease.PartitionId;

            try
            {
                string newToken;
                await leaseBlob.FetchAttributesAsync().ConfigureAwait(false);

                if (leaseBlob.Properties.LeaseState == LeaseState.Leased)
                {
                    if (string.IsNullOrEmpty(lease.Token))
                    {
                        // We reach here in a race condition: when this instance of EventProcessorHost scanned the
                        // lease blobs, this partition was unowned (token is empty) but between then and now, another
                        // instance of EPH has established a lease (getLeaseState() is LEASED). We normally enforce
                        // that we only steal the lease if it is still owned by the instance which owned it when we
                        // scanned, but we can't do that when we don't know who owns it. The safest thing to do is just
                        // fail the acquisition. If that means that one EPH instance gets more partitions than it should,
                        // rebalancing will take care of that quickly enough.
                        return(false);
                    }

                    ProcessorEventSource.Log.AzureStorageManagerInfo(this.host.HostName, lease.PartitionId, "Need to ChangeLease");
                    newToken = await leaseBlob.ChangeLeaseAsync(newLeaseId, AccessCondition.GenerateLeaseCondition(lease.Token)).ConfigureAwait(false);
                }
                else
                {
                    ProcessorEventSource.Log.AzureStorageManagerInfo(this.host.HostName, lease.PartitionId, "Need to AcquireLease");

                    try
                    {
                        newToken = await leaseBlob.AcquireLeaseAsync(leaseDuration, newLeaseId).ConfigureAwait(false);
                    }
                    catch (StorageException se)
                        when(se.RequestInformation != null &&
                             se.RequestInformation.ErrorCode.Equals(BlobErrorCodeStrings.LeaseAlreadyPresent, StringComparison.OrdinalIgnoreCase))
                        {
                            // Either some other host grabbed the lease or checkpoint call renewed it.
                            return(false);
                        }
                }

                lease.Token = newToken;
                lease.Owner = this.host.HostName;
                lease.IncrementEpoch(); // Increment epoch each time lease is acquired or stolen by a new host
                await leaseBlob.UploadTextAsync(JsonConvert.SerializeObject(lease), null, AccessCondition.GenerateLeaseCondition(lease.Token), null, null).ConfigureAwait(false);
            }
            catch (StorageException se)
            {
                throw HandleStorageException(partitionId, se);
            }

            return(retval);
        }
        private static async Task <bool> HandleConCurrencyForUpdate(CloudBlockBlob blockBlob, ConcurrencyType type)
        {
            bool result = false;

            switch (type)
            {
            case ConcurrencyType.Default:
                blockBlob.Metadata["Author"]   = "Default Update";
                blockBlob.Metadata["Priority"] = "High";
                await blockBlob.SetMetadataAsync();

                break;

            case ConcurrencyType.Optimistic:
                blockBlob.Metadata["Author"]   = "Optimistic Update";
                blockBlob.Metadata["Priority"] = "High";
                var accessCondition = new AccessCondition
                {
                    IfMatchETag = blockBlob.Properties.ETag
                };
                try
                {
                    await blockBlob.SetMetadataAsync(accessCondition, null, null);
                }
                catch (Exception exe)
                {
                    result = false;
                }

                break;

            case ConcurrencyType.Pessimistic:
                blockBlob.Metadata["Author"]   = "Optimistic Update";
                blockBlob.Metadata["Priority"] = "High";
                string leaseId = await blockBlob.AcquireLeaseAsync(TimeSpan.FromMinutes(1));

                var accessConditionPessimistic = new AccessCondition
                {
                    LeaseId = leaseId
                };
                try
                {
                    await blockBlob.SetMetadataAsync(accessConditionPessimistic, null, null);
                }
                catch (Exception exe)
                {
                    result = false;
                }

                //await blockBlob.BreakLeaseAsync(TimeSpan.FromSeconds(0));

                await blockBlob.ReleaseLeaseAsync(accessConditionPessimistic);

                break;
            }

            return(result);
        }
Beispiel #17
0
        public async Task <string> AcquireOneMinuteLeaseAsync(CloudBlockBlob cloudBlockBlob)
        {
            var accessCondition = new AccessCondition
            {
                IfMatchETag = cloudBlockBlob.Properties.ETag
            };

            return(await cloudBlockBlob.AcquireLeaseAsync(TimeSpan.FromMinutes(1), null, accessCondition, null, null));
        }
Beispiel #18
0
        /// <summary>
        /// Gets a reference to a blob created previously, and copies it to a new blob in the same container.
        /// </summary>
        /// <param name="container">A CloudBlobContainer object.</param>
        /// <param name="sourceBlobName"></param>
        /// <param name="destinationBlobName"></param>
        /// <returns>A Task object.</returns>
        private static async Task CopyBlockBlobAsync(CloudBlobContainer container,
                                                     string sourceBlobName,
                                                     string destinationBlobName)
        {
            CloudBlockBlob sourceBlob = null;
            CloudBlockBlob destBlob   = null;
            string         leaseId    = null;

            try
            {
                // Get a block blob from the container to use as the source.
                sourceBlob = container.GetBlockBlobReference(sourceBlobName);

                // Lease the source blob for the copy operation to prevent another client from modifying it.
                // Specifying null for the lease interval creates an infinite lease.
                leaseId = await sourceBlob.AcquireLeaseAsync(null);

                // Get a reference to a destination blob (in this case, a new blob).
                destBlob = container.GetBlockBlobReference(destinationBlobName);

                // Ensure that the source blob exists.
                if (await sourceBlob.ExistsAsync())
                {
                    // Get the ID of the copy operation.
                    string copyId = await destBlob.StartCopyAsync(sourceBlob);

                    // Fetch the destination blob's properties before checking the copy state.
                    await destBlob.FetchAttributesAsync();

                    Console.WriteLine("Status of copy operation: {0}", destBlob.CopyState.Status);
                    Console.WriteLine("Completion time: {0}", destBlob.CopyState.CompletionTime);
                    Console.WriteLine("Bytes copied: {0}", destBlob.CopyState.BytesCopied.ToString());
                    Console.WriteLine("Total bytes: {0}", destBlob.CopyState.TotalBytes.ToString());
                    Console.WriteLine();
                }
            }
            catch (StorageException e)
            {
                Console.WriteLine(e.Message);
                Console.ReadLine();
                throw;
            }
            finally
            {
                // Break the lease on the source blob.
                if (sourceBlob != null)
                {
                    await sourceBlob.FetchAttributesAsync();

                    if (sourceBlob.Properties.LeaseState != LeaseState.Available)
                    {
                        await sourceBlob.BreakLeaseAsync(new TimeSpan(0));
                    }
                }
            }
        }
Beispiel #19
0
        /// <summary>
        /// Makes a single attempt to get a lease.
        /// </summary>
        /// <returns></returns>
        public async Task <bool> GetLease()
        {
            var actualLease = string.Empty;

            try
            {
                actualLease = await _blob.AcquireLeaseAsync(_leaseTime, _leaseId);
            }
            catch (Exception ex)
            {
                Debug.Fail($"GetLease failed: {ex}");
            }

            return(StringComparer.Ordinal.Equals(_leaseId, actualLease));
        }
Beispiel #20
0
        public static async Task <bool> HandleConCurrencyUpdate(CloudBlockBlob blob, ConCurrencyType type)
        {
            bool result = false;

            switch (type)
            {
            case ConCurrencyType.Default:
                blob.Metadata["Author"]   = "Client Code";
                blob.Metadata["Priority"] = "High";
                blob.SetMetadata();
                break;

            case ConCurrencyType.Optimistic:
                blob.Metadata["Author"]   = "Client Code";
                blob.Metadata["Priority"] = "High";
                string leaseId = await blob.AcquireLeaseAsync(TimeSpan.FromMinutes(1));

                var accessCondition = new AccessCondition
                {
                    LeaseId = leaseId
                };
                await blob.SetMetadataAsync(accessCondition, null, null);

                break;

            case ConCurrencyType.Pessimistic:
                blob.Metadata["Author"]   = "Client Code";
                blob.Metadata["Priority"] = "High";
                var accessCondition1 = new AccessCondition
                {
                    IfMatchETag = blob.Properties.ETag
                };
                try
                {
                    await blob.SetMetadataAsync(accessCondition1, null, null);
                }
                catch (Exception exe)
                {
                    var cloudBlob = GetBlob();
                    await HandleConCurrencyUpdate(cloudBlob, ConCurrencyType.Pessimistic);

                    result = false;
                }
                break;
            }

            return(result);
        }
Beispiel #21
0
        public async Task <string> TryAcquireLeaseAsync(Uri resourceUri, string proposedLeaseId, CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(resourceUri, nameof(resourceUri));

            try
            {
                CloudBlockBlob blob = await GetCloudBlobClientAsync(resourceUri, cancellationToken);

                return(await blob.AcquireLeaseAsync(null, proposedLeaseId, cancellationToken));
            }
            catch (StorageException storageEx)
            {
                _logger.LogInformation(storageEx, "Failed to acquire lease on the blob {0}", resourceUri);
                return(null);
            }
        }
        public CloudBlockBlobLocker(CloudBlockBlob blob)
        {
            var exists = blob.ExistsAsync().Result;

            if (!exists)
            {
                blob.UploadTextAsync("{}").Wait();
                _isNew = true;
            }

            var lease = blob.AcquireLeaseAsync(TimeSpan.FromSeconds(15), null).Result;

            _accessCondition = AccessCondition.GenerateLeaseCondition(lease);

            _blob = blob;
        }
Beispiel #23
0
        private async Task ProcessBlob <T>(CloudBlockBlob blob, Action <T> updateFn, ILogger log) where T : new()
        {
            try
            {
                var exist = await blob.ExistsAsync();

                if (!exist)
                {
                    var data = new T();
                    var json = JsonConvert.SerializeObject(data);
                    await blob.UploadTextAsync(json);
                }
            }
            catch (Exception)
            {
            }

            var policy = Policy
                         .Handle <Exception>()
                         .WaitAndRetryForeverAsync((n) => TimeSpan.FromMilliseconds(100));

            var ac = await policy.ExecuteAsync(async() =>
            {
                var leaseId = await blob.AcquireLeaseAsync(TimeSpan.FromSeconds(30));
                if (string.IsNullOrEmpty(leaseId))
                {
                    throw new NullReferenceException();
                }

                return(AccessCondition.GenerateLeaseCondition(leaseId));
            });

            try
            {
                var input = await blob.DownloadTextAsync(ac, null, null);

                var data = JsonConvert.DeserializeObject <T>(input);
                updateFn(data);
                var output = JsonConvert.SerializeObject(data);
                await blob.UploadTextAsync(output, ac, null, null);
            }
            finally
            {
                await blob.ReleaseLeaseAsync(ac, null, null);
            }
        }
Beispiel #24
0
        public string AcquireLeaseOnBlob(
            string blob,
            TimeSpan?maxWaitDefault = null,
            TimeSpan?delayDefault   = null)
        {
            TimeSpan maxWait = maxWaitDefault ?? TimeSpan.FromSeconds(1800);
            TimeSpan delay   = delayDefault ?? TimeSpan.FromMilliseconds(500);

            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();

            // This will throw an exception with HTTP code 409 when we cannot acquire the lease
            // But we should block until we can get this lease, with a timeout (maxWaitSeconds)
            while (stopWatch.ElapsedMilliseconds < maxWait.TotalMilliseconds)
            {
                try
                {
                    CloudBlockBlob cloudBlob = _blobContainer.GetBlockBlobReference(blob);
                    System.Threading.Tasks.Task <string> task = cloudBlob.AcquireLeaseAsync(TimeSpan.FromMinutes(1), null);
                    task.Wait();

                    string leaseID = task.Result;

                    // Create a cancelabble task that will auto-renew the lease until the lease is released
                    _cancellationTokenSource = new CancellationTokenSource();
                    _leaseRenewalTask        = Task.Run(() =>
                                                        { AutoRenewLease(this, blob, leaseID); },
                                                        _cancellationTokenSource.Token);

                    return(leaseID);
                }
                catch (Exception e)
                {
                    Console.WriteLine($"Retrying lease acquisition on {blob}, {e.Message}");
                    Thread.Sleep(delay);
                }
            }

            ResetLeaseRenewalTaskState();

            throw new Exception($"Unable to acquire lease on {blob}");
        }
        async Task <bool> AcquireLeaseCoreAsync(AzureBlobLease lease)
        {
            CloudBlockBlob leaseBlob   = lease.Blob;
            bool           retval      = true;
            string         newLeaseId  = Guid.NewGuid().ToString();
            string         partitionId = lease.PartitionId;

            try
            {
                string newToken;
                await leaseBlob.FetchAttributesAsync().ConfigureAwait(false);

                if (leaseBlob.Properties.LeaseState == LeaseState.Leased)
                {
                    ProcessorEventSource.Log.AzureStorageManagerInfo(this.host.Id, lease.PartitionId, "Need to ChangeLease");
                    newToken = await leaseBlob.ChangeLeaseAsync(newLeaseId, AccessCondition.GenerateLeaseCondition(lease.Token)).ConfigureAwait(false);
                }
                else
                {
                    ProcessorEventSource.Log.AzureStorageManagerInfo(this.host.Id, lease.PartitionId, "Need to AcquireLease");
                    newToken = await leaseBlob.AcquireLeaseAsync(leaseDuration, newLeaseId).ConfigureAwait(false);
                }

                lease.Token = newToken;
                lease.Owner = this.host.HostName;
                lease.IncrementEpoch(); // Increment epoch each time lease is acquired or stolen by a new host
                await leaseBlob.UploadTextAsync(JsonConvert.SerializeObject(lease), null, AccessCondition.GenerateLeaseCondition(lease.Token), null, null).ConfigureAwait(false);
            }
            catch (StorageException se)
            {
                if (WasLeaseLost(partitionId, se))
                {
                    retval = false;
                }
                else
                {
                    throw;
                }
            }

            return(retval);
        }
        public async Task <BlobLease> AcquireBlobLeaseAsync(
            string fullPath,
            TimeSpan maxLeaseTime,
            bool waitForRelease = false,
            CancellationToken cancellationToken = default)
        {
            (CloudBlobContainer container, string path) = await GetPartsAsync(fullPath);

            CloudBlockBlob leaseBlob = container.GetBlockBlobReference(path);

            //if blob doesn't exist, just create an empty one
            if (!(await leaseBlob.ExistsAsync()))
            {
                await WriteAsync(fullPath, new MemoryStream(), false, cancellationToken);
            }

            string leaseId = null;

            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    leaseId = await leaseBlob.AcquireLeaseAsync(maxLeaseTime);

                    break;
                }
                catch (AzureStorageException asx) when(asx.RequestInformation.HttpStatusCode == 409)
                {
                    if (!waitForRelease)
                    {
                        throw new StorageException(ErrorCode.Conflict, asx);
                    }
                    else
                    {
                        await Task.Delay(TimeSpan.FromSeconds(1));
                    }
                }
            }

            return(new BlobLease(leaseBlob, leaseId));
        }
Beispiel #27
0
        public async Task <string> LeaseAsync(T key, TimeSpan leaseTime)
        {
            string         leaseName = GetLeaseName(key);
            CloudBlockBlob blob      = _container.GetBlockBlobReference(leaseName);

            try
            {
                string leaseId = await blob.AcquireLeaseAsync(leaseTime, Guid.NewGuid().ToString());

                _logger?.LogTrace("LeaseManager: LeaseAsync - acquired lease for key {KEY}", key);
                return(leaseId);
            }
            catch (StorageException ex)
            {
                if (ex.RequestInformation.HttpStatusCode == 400)
                {
                    _logger?.LogTrace("LeaseManager: LeaseAsync - failed to acquire lease for key {KEY}", key);
                    throw new UnableToAcquireLeaseException("Unable to acquire lease", ex);
                }
                throw;
            }
        }
        static async Task <string> AquireAsync(CloudBlockBlob blob, TimeSpan timeStamp)
        {
            bool retry = false;

            do
            {
                try
                {
                    return(await blob.AcquireLeaseAsync(timeStamp, null));
                }
                catch (StorageException e)
                {
                    WebException webException = e.InnerException as WebException;
                    if (webException != null)
                    {
                        HttpStatusCode statusCode = ((HttpWebResponse)webException.Response).StatusCode;
                        if (statusCode == HttpStatusCode.Conflict)
                        {
                            Thread.Sleep(500);
                            retry = true;
                        }
                        else if (statusCode == HttpStatusCode.NotFound)
                        {
                            blob.UploadText(string.Empty);
                            retry = true;
                        }
                    }
                    else
                    {
                        throw;
                    }
                }
            }while (retry);

            return(null);
        }
        async Task <bool> AcquireLeaseCoreAsync(AzureBlobLease lease)
        {
            CloudBlockBlob leaseBlob   = lease.Blob;
            bool           retval      = true;
            string         newLeaseId  = Guid.NewGuid().ToString();
            string         partitionId = lease.PartitionId;

            try
            {
                bool   renewLease = false;
                string newToken;

                await leaseBlob.FetchAttributesAsync(null, this.defaultRequestOptions, this.operationContext).ConfigureAwait(false);

                if (leaseBlob.Properties.LeaseState == LeaseState.Leased)
                {
                    if (string.IsNullOrEmpty(lease.Token))
                    {
                        // We reach here in a race condition: when this instance of EventProcessorHost scanned the
                        // lease blobs, this partition was unowned (token is empty) but between then and now, another
                        // instance of EPH has established a lease (getLeaseState() is LEASED). We normally enforce
                        // that we only steal the lease if it is still owned by the instance which owned it when we
                        // scanned, but we can't do that when we don't know who owns it. The safest thing to do is just
                        // fail the acquisition. If that means that one EPH instance gets more partitions than it should,
                        // rebalancing will take care of that quickly enough.
                        return(false);
                    }

                    ProcessorEventSource.Log.AzureStorageManagerInfo(this.host.HostName, lease.PartitionId, "Need to ChangeLease");
                    renewLease = true;
                    newToken   = await leaseBlob.ChangeLeaseAsync(
                        newLeaseId,
                        AccessCondition.GenerateLeaseCondition(lease.Token),
                        this.defaultRequestOptions,
                        this.operationContext).ConfigureAwait(false);
                }
                else
                {
                    ProcessorEventSource.Log.AzureStorageManagerInfo(this.host.HostName, lease.PartitionId, "Need to AcquireLease");
                    newToken = await leaseBlob.AcquireLeaseAsync(
                        leaseDuration,
                        newLeaseId,
                        null,
                        this.defaultRequestOptions,
                        this.operationContext).ConfigureAwait(false);
                }

                lease.Token = newToken;
                lease.Owner = this.host.HostName;
                lease.IncrementEpoch(); // Increment epoch each time lease is acquired or stolen by a new host

                // Renew lease here if needed?
                // ChangeLease doesn't renew so we should avoid lease expiring before next renew interval.
                if (renewLease)
                {
                    await this.RenewLeaseCoreAsync(lease).ConfigureAwait(false);
                }

                // Update owner in the metadata first since clients get ownership information by looking at metadata.
                lease.Blob.Metadata[MetaDataOwnerName] = lease.Owner;
                await lease.Blob.SetMetadataAsync(
                    AccessCondition.GenerateLeaseCondition(lease.Token),
                    this.defaultRequestOptions,
                    this.operationContext).ConfigureAwait(false);

                // Then update deserialized lease content.
                await leaseBlob.UploadTextAsync(
                    JsonConvert.SerializeObject(lease),
                    null,
                    AccessCondition.GenerateLeaseCondition(lease.Token),
                    this.defaultRequestOptions,
                    this.operationContext).ConfigureAwait(false);
            }
            catch (StorageException se)
            {
                throw HandleStorageException(partitionId, se);
            }

            return(retval);
        }
 /// <inheritdoc />
 public Task <string> AcquireLeaseAsync(TimeSpan?leaseTime, string proposedLeaseId,
                                        CancellationToken cancellationToken)
 {
     return(_sdk.AcquireLeaseAsync(leaseTime, proposedLeaseId, accessCondition: null, options: null, operationContext: null, cancellationToken: cancellationToken));
 }