Skip to content

Commit b1e021f

Browse files
authored
Add optional parameters to the ServiceCollection extensions (#27)
* Add optional parameters to the ServiceCollection extensions * Add optional parameters to the ServiceCollection extensions to configure dynamodb client. Fix warnings in unit tests by passing test cancellation token * add tests * update version prefix for new feature
1 parent d2556d4 commit b1e021f

7 files changed

Lines changed: 78 additions & 19 deletions

File tree

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<VersionPrefix>1.1.1</VersionPrefix>
3+
<VersionPrefix>1.1.2</VersionPrefix>
44
<PackageLicenseExpression>MIT</PackageLicenseExpression>
55

66
<!-- Other useful metadata -->

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,22 @@ Or bind from configuration:
4949
services.AddDynamoDbDistributedLock(configuration);
5050
```
5151

52+
If you need to customize the `IAmazonDynamoDB` client, you can pass in AWSOptions, or the configuration section name:
53+
54+
```csharp
55+
services.AddDynamoDbDistributedLock(configuration, awsOptionsSectionName: "DynamoDb");
56+
// or configure AWSOptions manually
57+
var awsOptions = configuration.GetAWSOptions("DynamoDb");
58+
awsOptions.DefaultClientConfig.ServiceURL = "http://localhost:4566"; // use localstack for testing
59+
services.AddDynamoDbDistributedLock(options =>
60+
{
61+
options.TableName = "my-lock-table";
62+
options.LockTimeoutSeconds = 30;
63+
options.PartitionKeyAttribute = "pk";
64+
options.SortKeyAttribute = "sk";
65+
}, awsOptions);
66+
```
67+
5268
### appsettings.json
5369
```json
5470
{

src/DynamoDb.DistributedLock/DynamoDbLockOptions.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ namespace DynamoDb.DistributedLock;
77
/// </summary>
88
public sealed class DynamoDbLockOptions
99
{
10+
/// <summary>
11+
/// The default name of the configuration section for DynamoDB lock settings.
12+
/// </summary>
1013
public const string DynamoDbLockSettings = "DynamoDbLock";
14+
1115
/// <summary>
1216
/// The name of the DynamoDB table to use.
1317
/// </summary>

src/DynamoDb.DistributedLock/Extensions/ServiceCollectionExtensions.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using Amazon.DynamoDBv2;
3+
using Amazon.Extensions.NETCore.Setup;
34
using Microsoft.Extensions.Configuration;
45
using Microsoft.Extensions.DependencyInjection;
56

@@ -16,25 +17,30 @@ public static class ServiceCollectionExtensions
1617
/// <param name="services">The service collection to register with.</param>
1718
/// <param name="configuration">The configuration source.</param>
1819
/// <param name="sectionName">The name of the configuration section to bind to <see cref="DynamoDbLockOptions"/>.</param>
20+
/// <param name="awsOptionsSectionName">The name of the configuration section to be read with GetAWSOptions</param>
1921
/// <returns>The updated <see cref="IServiceCollection"/>.</returns>
2022
public static IServiceCollection AddDynamoDbDistributedLock(this IServiceCollection services,
2123
IConfiguration configuration,
22-
string sectionName = DynamoDbLockOptions.DynamoDbLockSettings)
24+
string sectionName = DynamoDbLockOptions.DynamoDbLockSettings, string? awsOptionsSectionName = null)
2325
{
24-
return services.AddDynamoDbDistributedLock(options => configuration.GetSection(sectionName).Bind(options));
26+
var awsOptions = awsOptionsSectionName is not null
27+
? configuration.GetAWSOptions(awsOptionsSectionName)
28+
: null;
29+
return services.AddDynamoDbDistributedLock(options => configuration.GetSection(sectionName).Bind(options), awsOptions);
2530
}
2631

2732
/// <summary>
2833
/// Registers the DynamoDB distributed lock using a delegate to configure <see cref="DynamoDbLockOptions"/>.
2934
/// </summary>
3035
/// <param name="services">The service collection to register with.</param>
3136
/// <param name="configure">The delegate to configure <see cref="DynamoDbLockOptions"/>.</param>
37+
/// <param name="awsOptions">The AWSOptions to be used in configuring the dynamodb service client</param>
3238
/// <returns>The updated <see cref="IServiceCollection"/>.</returns>
3339
public static IServiceCollection AddDynamoDbDistributedLock(this IServiceCollection services,
34-
Action<DynamoDbLockOptions> configure)
40+
Action<DynamoDbLockOptions> configure, AWSOptions? awsOptions = null)
3541
{
3642
services.Configure(configure);
37-
services.AddAWSService<IAmazonDynamoDB>();
43+
services.AddAWSService<IAmazonDynamoDB>(awsOptions);
3844
services.AddSingleton<IDynamoDbDistributedLock, DynamoDbDistributedLock>();
3945
return services;
4046
}

test/DynamoDb.DistributedLock.Tests/Extensions/ServiceCollectionExtensionsTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using Amazon.DynamoDBv2;
2+
using Amazon.Extensions.NETCore.Setup;
3+
using Amazon.Runtime;
24
using DynamoDb.DistributedLock.Extensions;
35
using DynamoDb.DistributedLock.Tests.TestKit.Attributes;
46
using AwesomeAssertions;
@@ -120,4 +122,39 @@ public void AddDynamoDbDistributedLock_WithConfiguration_BindsCustomKeyAttribute
120122
options.PartitionKeyAttribute.Should().Be(partitionKey);
121123
options.SortKeyAttribute.Should().Be(sortKey);
122124
}
125+
126+
[Fact]
127+
public void AddDynamoDbDistributedLock_WithActionAndAwsConfig_SetsUpServiceAndOptions()
128+
{
129+
// Arrange
130+
var services = new ServiceCollection();
131+
var awsOptions = new AWSOptions
132+
{
133+
DefaultClientConfig = { ServiceURL = "http://localhost/" },
134+
// to allow the service client to be resolved without actual AWS credentials
135+
Credentials = new AnonymousAWSCredentials(),
136+
};
137+
138+
// Act
139+
services.AddDynamoDbDistributedLock(options =>
140+
{
141+
options.TableName = "locks";
142+
options.LockTimeoutSeconds = 45;
143+
}, awsOptions);
144+
145+
var provider = services.BuildServiceProvider();
146+
147+
// Assert
148+
var lockService = provider.GetService<IDynamoDbDistributedLock>();
149+
lockService.Should().NotBeNull();
150+
151+
var options = provider.GetRequiredService<IOptions<DynamoDbLockOptions>>().Value;
152+
options.TableName.Should().Be("locks");
153+
options.LockTimeoutSeconds.Should().Be(45);
154+
options.PartitionKeyAttribute.Should().Be("pk");
155+
options.SortKeyAttribute.Should().Be("sk");
156+
157+
var dynamoDbClient = provider.GetRequiredService<IAmazonDynamoDB>();
158+
dynamoDbClient.Config.ServiceURL.Should().Be("http://localhost/");
159+
}
123160
}

test/DynamoDb.DistributedLock.Tests/Retry/ExponentialBackoffRetryPolicyTests.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,11 @@ public async Task ExecuteAsync_WhenOperationSucceedsOnFirstAttempt_ShouldReturnR
5050
var sut = new ExponentialBackoffRetryPolicy(options);
5151
var operationCalled = 0;
5252

53-
var result = await sut.ExecuteAsync(
54-
_ =>
53+
var result = await sut.ExecuteAsync(_ =>
5554
{
5655
operationCalled++;
5756
return Task.FromResult(expectedResult);
58-
},
59-
_ => true);
57+
}, _ => true, TestContext.Current.CancellationToken);
6058

6159
result.Should().Be(expectedResult);
6260
operationCalled.Should().Be(1);
@@ -120,15 +118,13 @@ public async Task ExecuteAsync_WhenOperationSucceedsAfterRetries_ShouldReturnRes
120118
var sut = new ExponentialBackoffRetryPolicy(options);
121119
var operationCalled = 0;
122120

123-
var result = await sut.ExecuteAsync(
124-
_ =>
121+
var result = await sut.ExecuteAsync(_ =>
125122
{
126123
operationCalled++;
127124
if (operationCalled < 3)
128125
throw new InvalidOperationException("Retry me");
129126
return Task.FromResult(expectedResult);
130-
},
131-
_ => true);
127+
}, _ => true, TestContext.Current.CancellationToken);
132128

133129
result.Should().Be(expectedResult);
134130
operationCalled.Should().Be(3);

test/DynamoDb.DistributedLock.Tests/Retry/RetryIntegrationTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public async Task AcquireLockAsync_WhenRetryDisabled_ShouldNotRetryOnFailure(
3131
var sut = new DynamoDbDistributedLock(dynamo, options);
3232

3333
// Act
34-
var result = await sut.AcquireLockAsync(resourceId, ownerId);
34+
var result = await sut.AcquireLockAsync(resourceId, ownerId, TestContext.Current.CancellationToken);
3535

3636
// Assert
3737
result.Should().BeFalse();
@@ -64,7 +64,7 @@ public async Task AcquireLockAsync_WhenRetryEnabledAndEventuallySucceeds_ShouldR
6464
var sut = new DynamoDbDistributedLock(dynamo, options);
6565

6666
// Act
67-
var result = await sut.AcquireLockAsync(resourceId, ownerId);
67+
var result = await sut.AcquireLockAsync(resourceId, ownerId, TestContext.Current.CancellationToken);
6868

6969
// Assert
7070
result.Should().BeTrue();
@@ -90,7 +90,7 @@ public async Task AcquireLockAsync_WhenRetryEnabledButMaxAttemptsReached_ShouldR
9090
var sut = new DynamoDbDistributedLock(dynamo, options);
9191

9292
// Act
93-
var result = await sut.AcquireLockAsync(resourceId, ownerId);
93+
var result = await sut.AcquireLockAsync(resourceId, ownerId, TestContext.Current.CancellationToken);
9494

9595
// Assert
9696
result.Should().BeFalse();
@@ -123,7 +123,7 @@ public async Task AcquireLockAsync_WhenRetryEnabledWithThrottling_ShouldRetryOnP
123123
var sut = new DynamoDbDistributedLock(dynamo, options);
124124

125125
// Act
126-
var result = await sut.AcquireLockAsync(resourceId, ownerId);
126+
var result = await sut.AcquireLockAsync(resourceId, ownerId, TestContext.Current.CancellationToken);
127127

128128
// Assert
129129
result.Should().BeTrue();
@@ -180,7 +180,7 @@ public async Task AcquireLockHandleAsync_WhenRetryEnabledAndSucceeds_ShouldRetur
180180
var sut = new DynamoDbDistributedLock(dynamo, options);
181181

182182
// Act
183-
var result = await sut.AcquireLockHandleAsync(resourceId, ownerId);
183+
var result = await sut.AcquireLockHandleAsync(resourceId, ownerId, TestContext.Current.CancellationToken);
184184

185185
// Assert
186186
result.Should().NotBeNull();
@@ -209,7 +209,7 @@ public async Task AcquireLockAsync_WhenRetryEnabledAndThrottlingExhaustsRetries_
209209
var sut = new DynamoDbDistributedLock(dynamo, options);
210210

211211
// Act
212-
var result = await sut.AcquireLockAsync(resourceId, ownerId);
212+
var result = await sut.AcquireLockAsync(resourceId, ownerId, TestContext.Current.CancellationToken);
213213

214214
// Assert
215215
result.Should().BeFalse();

0 commit comments

Comments
 (0)