/// <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)); }
public void GivenTheNameOnTheLeasePolicyIs(string name) { var policy = new LeasePolicy { Name = name }; ScenarioContext.Current.Set(policy); }
public void GivenTheDurationOnTheLeasePolicyIsSeconds(int leaseDurationInSeconds) { var policy = new LeasePolicy { Duration = TimeSpan.FromSeconds(leaseDurationInSeconds) }; ScenarioContext.Current.Set(policy); }
public void GivenTheDurationOnTheLeasePolicyIsNull() { var policy = new LeasePolicy { Duration = null }; ScenarioContext.Current.Set(policy); }
public void GivenIAmTheOnlyActorTryingToPerformAnOperationCalled(string leaseName) { var policy = new LeasePolicy { Name = leaseName }; ScenarioContext.Current.Set(policy); }
public void GivenIAmActorBTryingToPerformAnOperationCalled(string leaseName) { leaseName += $"_{Guid.NewGuid()}"; var policy = new LeasePolicy { Name = leaseName }; this.scenarioContext.Set(policy); }
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"); }
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"); }
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); }
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); }
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); }
/// <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)); }
/// <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; }
/// <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(); }
/// <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; } }
/// <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; }
public void GivenTheNameOnTheLeasePolicyIsNull() { var policy = new LeasePolicy(); ScenarioContext.Current.Set(policy); }