Exemple #1
0
        private async Task <bool> ReleaseLeaseAsync(AzureBlobLease lease)
        {
            if (string.IsNullOrWhiteSpace(lease.Token))
            {
                return(false);
            }

            var leaseBlob = lease.Blob;
            var key       = lease.Key;

            try
            {
                var leaseId      = lease.Token;
                var releasedCopy = new AzureBlobLease(lease)
                {
                    Token = string.Empty
                };

                await SetBlobStateAsync(releasedCopy, leaseId).ConfigureAwait(false);

                await leaseBlob.GetBlobLeaseClient(leaseId).ReleaseAsync().ConfigureAwait(false);
            }
            catch (RequestFailedException se)
            {
                throw HandleStorageException(key, se);
            }

            return(true);
        }
Exemple #2
0
        private async Task <AzureBlobLease> CreateLeaseIfNotExistsAsync(string key) // throws URISyntaxException, IOException, StorageException
        {
            AzureBlobLease returnLease;

            try
            {
                var leaseBlob = GetBlockBlobReference(key);
                returnLease = new AzureBlobLease(key, leaseBlob);
                var jsonLease = JsonConvert.SerializeObject(returnLease);

                if (await leaseBlob.ExistsAsync(CancellationToken.None))
                {
                    return(await GetLeaseAsync(key).ConfigureAwait(false));
                }

                await SetBlobStateAsync(returnLease).ConfigureAwait(false);
            }
            catch (RequestFailedException se)
            {
                if (se.ErrorCode == BlobErrorCode.BlobAlreadyExists ||
                    se.ErrorCode == BlobErrorCode.LeaseIdMissing) // occurs when somebody else already has leased the blob
                {
                    returnLease = await GetLeaseAsync(key).ConfigureAwait(false);
                }
                else
                {
                    throw;
                }
            }

            return(returnLease);
        }
        private async Task <bool> ReleaseLeaseAsync(AzureBlobLease lease)
        {
            if (string.IsNullOrWhiteSpace(lease.Token))
            {
                return(false);
            }

            var leaseBlob = lease.Blob;
            var key       = lease.Key;

            try
            {
                var leaseId      = lease.Token;
                var releasedCopy = new AzureBlobLease(lease)
                {
                    Token = string.Empty
                };
                await leaseBlob.UploadTextAsync(
                    JsonConvert.SerializeObject(releasedCopy),
                    null,
                    AccessCondition.GenerateLeaseCondition(leaseId),
                    null,
                    _storageContext).ConfigureAwait(false);

                await leaseBlob.ReleaseLeaseAsync(AccessCondition.GenerateLeaseCondition(leaseId)).ConfigureAwait(false);
            }
            catch (StorageException se)
            {
                throw HandleStorageException(key, se);
            }

            return(true);
        }
        private async Task <bool> AcquireLeaseAsync(AzureBlobLease lease)
        {
            var leaseBlob  = lease.Blob;
            var newLeaseId = Guid.NewGuid().ToString();
            var lockerKey  = lease.Key;

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

                if (leaseBlob.Properties.LeaseState == LeaseState.Leased)
                {
                    if (string.IsNullOrEmpty(lease.Token))
                    {
                        return(false);
                    }

                    newToken = await leaseBlob.ChangeLeaseAsync(
                        newLeaseId,
                        AccessCondition.GenerateLeaseCondition(lease.Token),
                        null,
                        _storageContext).ConfigureAwait(false);
                }
                else
                {
                    try
                    {
                        newToken = await leaseBlob.AcquireLeaseAsync(
                            Options.LeaseDuration,
                            newLeaseId,
                            null,
                            null,
                            _storageContext)
                                   .ConfigureAwait(false);
                    }
                    catch (StorageException se)
                        when(se.RequestInformation != null &&
                             se.RequestInformation.ErrorCode.Equals(BlobErrorCodeStrings.LeaseAlreadyPresent, StringComparison.OrdinalIgnoreCase))
                        {
                            return(false);
                        }
                }

                lease.Token = newToken;
                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,
                    _storageContext).ConfigureAwait(false);
            }
            catch (StorageException se)
            {
                throw HandleStorageException(lockerKey, se);
            }

            return(true);
        }
        private static async Task <AzureBlobLease> DownloadLeaseAsync(CloudBlockBlob blob) // throws StorageException, IOException
        {
            var jsonLease = await blob.DownloadTextAsync().ConfigureAwait(false);

            var rehydrated = (AzureBlobLease)JsonConvert.DeserializeObject(jsonLease, typeof(AzureBlobLease));
            var blobLease  = new AzureBlobLease(rehydrated, blob);

            return(blobLease);
        }
Exemple #6
0
        private static async Task <AzureBlobLease> DownloadLeaseAsync(BlockBlobClient blob) // throws StorageException, IOException
        {
            var jsonLease = await blob.DownloadAsync().ConfigureAwait(false);

            using (var stream = new StreamReader(jsonLease.Value.Content))
            {
                var rehydrated = (AzureBlobLease)JsonConvert.DeserializeObject(stream.ReadToEnd(), typeof(AzureBlobLease));
                var blobLease  = new AzureBlobLease(rehydrated, blob);

                return(blobLease);
            }
        }
Exemple #7
0
        private async Task <AzureBlobLease> GetLeaseAsync(string key) // throws URISyntaxException, IOException, StorageException
        {
            AzureBlobLease result    = null;
            var            leaseBlob = GetBlockBlobReference(key);

            if (await leaseBlob.ExistsAsync().ConfigureAwait(false))
            {
                result = await DownloadLeaseAsync(leaseBlob).ConfigureAwait(false);
            }

            return(result);
        }
Exemple #8
0
        private async Task <bool> AcquireLeaseAsync(AzureBlobLease lease)
        {
            var leaseBlob  = lease.Blob;
            var newLeaseId = Guid.NewGuid().ToString();
            var lockerKey  = lease.Key;

            try
            {
                string newToken;
                var    props = await leaseBlob.GetPropertiesAsync().ConfigureAwait(false);

                if (props.Value.LeaseState == LeaseState.Leased)
                {
                    if (string.IsNullOrEmpty(lease.Token))
                    {
                        return(false);
                    }

                    var response = await leaseBlob.GetBlobLeaseClient(lease.Token).ChangeAsync(newLeaseId);

                    newToken = response.Value.LeaseId;
                }
                else
                {
                    try
                    {
                        var response = await leaseBlob.GetBlobLeaseClient(lease.Token).AcquireAsync(Options.LeaseDuration).ConfigureAwait(false);

                        newToken = response.Value.LeaseId;
                    }
                    catch (RequestFailedException se)
                        when(se != null &&
                             se.ErrorCode == BlobErrorCode.LeaseAlreadyPresent)
                        {
                            return(false);
                        }
                }

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

                await SetBlobStateAsync(lease).ConfigureAwait(false);
            }
            catch (RequestFailedException se)
            {
                throw HandleStorageException(lockerKey, se);
            }

            return(true);
        }
Exemple #9
0
        /// <inheritdoc cref="IDistributedLock" />
        public async Task <T> ExecuteAsync <T>(Func <IDistributedLockContext, Task <T> > result)
        {
            try
            {
                // if the task is executed within the same process we can lock by code each operation avoiding internal http calls if
                // there is a single competitor node
                await _semaphore.WaitAsync().ConfigureAwait(false);

                var lease = await CreateLeaseIfNotExistsAsync(Options.Key).ConfigureAwait(false);

                _currentLease = lease;
                var operationPerformed = false;
                var value = default(T);

                var attempts = 0;
                while (!operationPerformed && attempts <= Options.RetryTimes)
                {
                    try
                    {
                        attempts++;
                        var acquired = await AcquireLeaseAsync(lease).ConfigureAwait(false);

                        if (acquired)
                        {
                            operationPerformed = true;
                            value = await result.Invoke(_currentContext).ConfigureAwait(false);
                        }
                    }
                    finally
                    {
                        await ReleaseLeaseAsync(lease).ConfigureAwait(false);
                    }

                    if (!operationPerformed)
                    {
                        await Task.Delay(Options.RetryWaitTime).ConfigureAwait(false);
                    }
                }

                return(value);
            }
            finally
            {
                _semaphore.Release();
            }
        }
Exemple #10
0
        private async Task SetBlobStateAsync(AzureBlobLease lease, string leaseId = null)
        {
            // if lease id is not sent then use the current lease token
            if (leaseId == null)
            {
                leaseId = lease.Token;
            }

            using (var uploadFileStream = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(lease) ?? "")))
            {
                var options = new BlobUploadOptions()
                {
                    Conditions = new BlobRequestConditions()
                    {
                        LeaseId = leaseId
                    }
                };

                await lease.Blob.UploadAsync(uploadFileStream, options).ConfigureAwait(false);
            }
        }
        private async Task <AzureBlobLease> CreateLeaseIfNotExistsAsync(string key) // throws URISyntaxException, IOException, StorageException
        {
            AzureBlobLease returnLease;

            try
            {
                var leaseBlob = GetBlockBlobReference(key);
                returnLease = new AzureBlobLease(key, leaseBlob);
                var jsonLease = JsonConvert.SerializeObject(returnLease);

                if (await leaseBlob.ExistsAsync(CancellationToken.None))
                {
                    return(await GetLeaseAsync(key).ConfigureAwait(false));
                }

                await leaseBlob.UploadTextAsync(
                    jsonLease,
                    null,
                    AccessCondition.GenerateIfNoneMatchCondition("*"),
                    null,
                    _storageContext).ConfigureAwait(false);
            }
            catch (StorageException se)
            {
                if (se.RequestInformation.ErrorCode == BlobErrorCodeStrings.BlobAlreadyExists ||
                    se.RequestInformation.ErrorCode == BlobErrorCodeStrings.LeaseIdMissing) // occurs when somebody else already has leased the blob
                {
                    returnLease = await GetLeaseAsync(key).ConfigureAwait(false);
                }
                else
                {
                    throw;
                }
            }

            return(returnLease);
        }
Exemple #12
0
 internal AzureBlobLease(AzureBlobLease source)
     : base(source)
 {
     Offset = source.Offset;
     Blob = source.Blob;
 }