예제 #1
0
        /// <summary>
        /// Creates an <see cref="InMemoryLease"/> from a lease token.
        /// </summary>
        /// <param name="leaseProvider">The lease provider.</param>
        /// <param name="token">The lease token from which to construct the lease.</param>
        /// <returns>An instance of an in-memory lease configured from the lease token.</returns>
        internal static InMemoryLease FromToken(InMemoryLeaseProvider leaseProvider, string token)
        {
            if (leaseProvider is null)
            {
                throw new ArgumentNullException(nameof(leaseProvider));
            }

            if (token is null)
            {
                throw new ArgumentNullException(nameof(token));
            }

            string tokenizedLease = token.Base64UrlDecode();

            string[] lines = tokenizedLease.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
            if (lines[0] != LeaseTokenContentType)
            {
                throw new TokenizationException();
            }

            string         id           = lines[1];
            DateTimeOffset?lastAcquired = lines[2] != NullString ? (DateTimeOffset?)DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(lines[2])) : null;
            var            leasePolicy  = new LeasePolicy
            {
                Name      = lines[5],
                ActorName = lines[3],
                Duration  = lines[4] != NullString ? (TimeSpan?)TimeSpan.FromMilliseconds(long.Parse(lines[4])) : null,
            };

            return(new InMemoryLease(leaseProvider, leasePolicy, id, lastAcquired));
        }
예제 #2
0
        public void GivenTheNameOnTheLeasePolicyIs(string name)
        {
            var policy = new LeasePolicy {
                Name = name
            };

            ScenarioContext.Current.Set(policy);
        }
예제 #3
0
        public void GivenTheDurationOnTheLeasePolicyIsSeconds(int leaseDurationInSeconds)
        {
            var policy = new LeasePolicy {
                Duration = TimeSpan.FromSeconds(leaseDurationInSeconds)
            };

            ScenarioContext.Current.Set(policy);
        }
예제 #4
0
        public void GivenTheDurationOnTheLeasePolicyIsNull()
        {
            var policy = new LeasePolicy {
                Duration = null
            };

            ScenarioContext.Current.Set(policy);
        }
예제 #5
0
        public void GivenIAmTheOnlyActorTryingToPerformAnOperationCalled(string leaseName)
        {
            var policy = new LeasePolicy {
                Name = leaseName
            };

            ScenarioContext.Current.Set(policy);
        }
예제 #6
0
        public void GivenIAmActorBTryingToPerformAnOperationCalled(string leaseName)
        {
            leaseName += $"_{Guid.NewGuid()}";
            var policy = new LeasePolicy {
                Name = leaseName
            };

            this.scenarioContext.Set(policy);
        }
예제 #7
0
        public void GivenActorAHasAlreadyAcquiredALeaseForAnOperationCalled(string leaseName)
        {
            var policy = new LeasePolicy {
                Name = leaseName, Duration = TimeSpan.FromSeconds(15)
            };
            var lease = new Lease(new AzureLeaseProvider(new ConnectionStringProvider()), new AzureLeasePolicyValidator());

            lease.AcquireAsync(policy).Wait();
            ScenarioContext.Current.Set(lease, "ActorALease");
        }
예제 #8
0
        public async Task GivenActorAHasAlreadyAcquiredALeaseForAnOperationWithTheSameName()
        {
            var otherPolicy = this.scenarioContext.Get <LeasePolicy>();
            var policy      = new LeasePolicy {
                Name = otherPolicy.Name, Duration = TimeSpan.FromSeconds(15)
            };
            var leaseProvider = ContainerBindings.GetServiceProvider(this.featureContext).GetRequiredService <ILeaseProvider>();
            var lease         = await leaseProvider.AcquireAsync(policy);

            this.scenarioContext.Set(lease, "ActorALease");
        }
예제 #9
0
        public void GivenIAmTheOnlyActorTryingToPerformAnOperationCalled(string leaseName)
        {
            if (leaseName.EndsWith("."))
            {
                leaseName  = leaseName.Remove(leaseName.Length - 1, 1);
                leaseName += $"_{Guid.NewGuid()}.";
            }
            else
            {
                leaseName += $"_{Guid.NewGuid()}";
            }

            var policy = new LeasePolicy {
                Name = leaseName
            };

            this.scenarioContext.Set(policy);
        }
예제 #10
0
        public void GivenActorAExecutesTheTaskWithOptions()
        {
            var provider = ContainerBindings.GetServiceProvider(this.featureContext).GetRequiredService <ILeaseProvider>();

            string         leaseName;
            TimeSpan       leaseDuration;
            IRetryPolicy   retryPolicy;
            IRetryStrategy retryStrategy;

            this.scenarioContext.TryGetValue(LeaseName, out leaseName);
            this.scenarioContext.TryGetValue(LeaseDuration, out leaseDuration);
            this.scenarioContext.TryGetValue(RetryPolicy, out retryPolicy);
            this.scenarioContext.TryGetValue(RetryStrategy, out retryStrategy);

            var policy = new LeasePolicy {
                Name = leaseName, ActorName = "Actor A", Duration = leaseDuration
            };

            var task = provider.ExecuteWithMutexAsync(this.DoSomething, policy, retryStrategy, retryPolicy);

            SetContinuations(this.scenarioContext, task);
            AddToTasks(this.scenarioContext, task);
        }
예제 #11
0
        public async Task WhenIExecuteTheTaskWithOptions()
        {
            var provider = ContainerBindings.GetServiceProvider(this.featureContext).GetRequiredService <ILeaseProvider>();

            string         leaseName;
            TimeSpan       leaseDuration;
            IRetryPolicy   retryPolicy;
            IRetryStrategy retryStrategy;
            LeasePolicy    policy = null;

            this.scenarioContext.TryGetValue(LeaseName, out leaseName);
            this.scenarioContext.TryGetValue(LeaseDuration, out leaseDuration);
            this.scenarioContext.TryGetValue(RetryPolicy, out retryPolicy);
            this.scenarioContext.TryGetValue(RetryStrategy, out retryStrategy);

            if (leaseName != null || leaseDuration != default(TimeSpan))
            {
                policy = new LeasePolicy {
                    Name = leaseName, ActorName = "Actor A", Duration = leaseDuration
                };
            }

            try
            {
                await provider.ExecuteWithMutexAsync(this.DoSomething, policy, retryStrategy, retryPolicy);
            }
            catch (AggregateException ex)
            {
                this.scenarioContext.Add("AggregateException", ex);
            }
            catch (Exception ex)
            {
                this.scenarioContext.Add("Exception", ex);
            }

            this.scenarioContext.Set(true, Result);
        }
예제 #12
0
 /// <summary>
 /// Initializes a new instance of the <see cref="AzureLease"/> class.
 /// </summary>
 /// <param name="leaseProvider">The lease provider.</param>
 /// <param name="leasePolicy">The lease policy.</param>
 /// <param name="id">The id for the lease.</param>
 internal AzureLease(AzureLeaseProvider leaseProvider, LeasePolicy leasePolicy, string id)
     : base(leaseProvider, leasePolicy, id)
 {
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="LeaseAcquisitionUnsuccessfulException"/> class.
 /// </summary>
 /// <param name="leasePolicy">The lease policy used during the attempt to acquire the lease.</param>
 /// <param name="innerException">Exception that cause the lease to be unsuccessfully acquired.</param>
 public LeaseAcquisitionUnsuccessfulException(LeasePolicy leasePolicy, Exception?innerException)
     : base(string.Empty, innerException)
 {
     this.LeasePolicy = leasePolicy ?? throw new ArgumentNullException(nameof(leasePolicy));
 }
예제 #14
0
 /// <summary>
 /// Initializes a new instance of the <see cref="InMemoryLease"/> class.
 /// </summary>
 /// <param name="leaseProvider">
 /// The lease provider.
 /// </param>
 /// <param name="leasePolicy">
 /// The lease policy.
 /// </param>
 /// <param name="id">
 /// The id.
 /// </param>
 /// <param name="lastAcquired">The time at which the lease was last acquired.</param>
 public InMemoryLease(InMemoryLeaseProvider leaseProvider, LeasePolicy leasePolicy, string id, DateTimeOffset?lastAcquired)
     : base(leaseProvider, leasePolicy, id)
 {
     this.lastAcquired = lastAcquired;
 }
예제 #15
0
 /// <summary>
 /// Initializes a new instance of the <see cref="InMemoryLease"/> class.
 /// </summary>
 /// <param name="leaseProvider">
 /// The lease provider.
 /// </param>
 /// <param name="leasePolicy">
 /// The lease policy.
 /// </param>
 /// <param name="id">
 /// The id.
 /// </param>
 public InMemoryLease(InMemoryLeaseProvider leaseProvider, LeasePolicy leasePolicy, string id)
     : base(leaseProvider, leasePolicy, id)
 {
     this.SetLastAcquired();
 }
예제 #16
0
        /// <inheritdoc/>
        public async Task <Lease> AcquireAsync(LeasePolicy leasePolicy, string?proposedLeaseId = null)
        {
            if (leasePolicy is null)
            {
                throw new ArgumentNullException(nameof(leasePolicy));
            }

            this.logger.LogDebug($"Acquiring lease for '{leasePolicy.ActorName}' with name '{leasePolicy.Name}', duration '{leasePolicy.Duration}', and proposed id '{proposedLeaseId}'");

            try
            {
                await this.InitialiseAsync().ConfigureAwait(false);

                // Once Initialise has been called, we know this.container is set.
                CloudBlockBlob blob = this.container !.GetBlockBlobReference((leasePolicy.Name ?? Guid.NewGuid().ToString()).ToLowerInvariant());

                await Retriable.RetryAsync(
                    async() =>
                {
                    try
                    {
                        if (!await blob.ExistsAsync().ConfigureAwait(false))
                        {
                            using var ms = new MemoryStream();
                            await blob.UploadFromStreamAsync(ms).ConfigureAwait(false);
                        }
                    }
                    catch (StorageException ex) when(ex.RequestInformation.HttpStatusCode == 400)
                    {
                        // Turn that into an invalid operation exception for standard "bad request" semantics (bad name)
                        throw new InvalidOperationException();
                    }
                    catch (ArgumentOutOfRangeException)
                    {
                        // Turn that into an invalid operation exception for standard "bad request" semantics (bad duration)
                        throw new InvalidOperationException();
                    }
                },
                    CancellationToken.None,
                    new Count(10),
                    new AggregatePolicy { Policies = { new DoNotRetryOnInvalidOperationPolicy(), new DoNotRetryOnConflictPolicy(), new DoNotRetryOnInitializationFailurePolicy() } }).ConfigureAwait(false);

                string id = await Retriable.RetryAsync(
                    async() =>
                {
                    try
                    {
                        return(await blob.AcquireLeaseAsync(leasePolicy.Duration, proposedLeaseId));
                    }
                    catch (StorageException ex) when(ex.RequestInformation.HttpStatusCode == 400)
                    {
                        // Turn that into an invalid operation exception for standard "bad request" semantics (bad name)
                        throw new InvalidOperationException();
                    }
                    catch (ArgumentOutOfRangeException)
                    {
                        // Turn that into an invalid operation exception for standard "bad request" semantics (bad duration)
                        throw new InvalidOperationException();
                    }
                },
                    CancellationToken.None,
                    new Count(10),
                    new AggregatePolicy { Policies = { new DoNotRetryOnInvalidOperationPolicy(), new DoNotRetryOnConflictPolicy(), new DoNotRetryOnInitializationFailurePolicy() } }).ConfigureAwait(false);

                var lease = new AzureLease(this, leasePolicy, id);
                lease.SetLastAcquired(DateTimeOffset.Now);

                this.logger.LogDebug($"Acquired lease for '{leasePolicy.ActorName}' with name '{leasePolicy.Name}', duration '{leasePolicy.Duration}', and actual id '{id}'");

                return(lease);
            }
            catch (StorageException exception)
            {
                if (exception.RequestInformation.HttpStatusCode == 409)
                {
                    this.logger.LogError($"Failed to acquire lease for '{leasePolicy.ActorName}'. The lease was held by another party. The lease name was '{leasePolicy.Name}', duration '{leasePolicy.Duration}', and proposed id '{proposedLeaseId}'");
                    throw new LeaseAcquisitionUnsuccessfulException(leasePolicy, exception);
                }
                else
                {
                    this.logger.LogError($"Failed to acquire lease for '{leasePolicy.ActorName}' due to storage failure. The lease name was '{leasePolicy.Name}', duration '{leasePolicy.Duration}', and proposed id '{proposedLeaseId}'");
                    throw;
                }
            }
            catch (InitializationFailureException)
            {
                this.logger.LogError($"Failed to acquire lease for '{leasePolicy.ActorName}' due to storage intiialization failure. The lease name was '{leasePolicy.Name}', duration '{leasePolicy.Duration}', and proposed id '{proposedLeaseId}'");
                throw;
            }
        }
예제 #17
0
 /// <summary>
 /// Initializes a new instance of the <see cref="AzureLease"/> class.
 /// </summary>
 /// <param name="leaseProvider">The lease provider.</param>
 /// <param name="leasePolicy">The lease policy.</param>
 /// <param name="id">The id for the lease.</param>
 /// <param name="lastAcquired">The time at which the lease was last acquired.</param>
 internal AzureLease(AzureLeaseProvider leaseProvider, LeasePolicy leasePolicy, string id, DateTimeOffset?lastAcquired)
     : base(leaseProvider, leasePolicy, id)
 {
     this.lastAcquired = lastAcquired;
 }
예제 #18
0
        public void GivenTheNameOnTheLeasePolicyIsNull()
        {
            var policy = new LeasePolicy();

            ScenarioContext.Current.Set(policy);
        }