Skip to content

Commit b78bb7d

Browse files
committed
feat(Cachula.Redis): make CachulaRedisCacheSettings.BatchSize configurable
1 parent 7928a36 commit b78bb7d

File tree

3 files changed

+82
-7
lines changed

3 files changed

+82
-7
lines changed

src/Cachula.Redis/CachulaRedisCache.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,18 @@ public class CachulaRedisCache : ICachulaDistributedCache
1414
{
1515
private readonly IDatabase _redisDatabase;
1616
private readonly JsonSerializerOptions _serializerOptions;
17-
private readonly CachulaRedisCacheSettings _settings = new()
18-
{
19-
// TODO: Make it configurable via DI or options pattern.
20-
BatchSize = 100,
21-
};
17+
private readonly CachulaRedisCacheSettings _settings;
2218

2319
/// <summary>
2420
/// Initializes a new instance of the <see cref="CachulaRedisCache"/> class.
2521
/// </summary>
2622
/// <param name="redisDatabase">The Redis database instance.</param>
2723
/// <param name="serializerOptions">Optional serializer options for JSON serialization.</param>
24+
/// <param name="settings">Optional settings for Cachula Redis cache (e.g., BatchSize).</param>
2825
/// <remarks>
2926
/// This constructor requires an instance of <see cref="IDatabase"/> from StackExchange.Redis.
3027
/// </remarks>
31-
public CachulaRedisCache(IDatabase redisDatabase, JsonSerializerOptions? serializerOptions = null)
28+
public CachulaRedisCache(IDatabase redisDatabase, JsonSerializerOptions? serializerOptions = null, CachulaRedisCacheSettings? settings = null)
3229
{
3330
_redisDatabase = redisDatabase ?? throw new ArgumentNullException(nameof(redisDatabase));
3431
_serializerOptions = serializerOptions ?? new JsonSerializerOptions
@@ -38,6 +35,11 @@ public CachulaRedisCache(IDatabase redisDatabase, JsonSerializerOptions? seriali
3835
//// This helps reduce payload size and avoids unnecessary data storage.
3936
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
4037
};
38+
_settings = settings ?? new CachulaRedisCacheSettings();
39+
if (_settings.BatchSize <= 0)
40+
{
41+
throw new ArgumentOutOfRangeException(nameof(settings), "BatchSize must be greater than zero.");
42+
}
4143
}
4244

4345
/// <inheritdoc />

src/Cachula/Configurations/CachulaRedisCacheSettings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ public class CachulaRedisCacheSettings
88
/// <summary>
99
/// Gets the batch size for Redis cache operations.
1010
/// </summary>
11-
public int BatchSize { get; init; }
11+
public int BatchSize { get; init; } = 100;
1212
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using Cachula.Configurations;
2+
using StackExchange.Redis;
3+
4+
namespace Cachula.Redis.Tests.CachulaRedisCacheTests;
5+
6+
[TestFixture]
7+
public class CachulaRedisCache_BatchSize_Tests
8+
{
9+
[Test]
10+
public void Ctor_ThrowsArgumentOutOfRange_WhenBatchSizeIsZeroOrNegative()
11+
{
12+
var db = Substitute.For<IDatabase>();
13+
14+
Assert.Throws<ArgumentOutOfRangeException>(() => new CachulaRedisCache(db, settings: new CachulaRedisCacheSettings { BatchSize = 0 }));
15+
Assert.Throws<ArgumentOutOfRangeException>(() => new CachulaRedisCache(db, settings: new CachulaRedisCacheSettings { BatchSize = -5 }));
16+
}
17+
18+
[Test]
19+
public async Task SetManyAsync_SplitsIntoBatches_BySettingsBatchSize()
20+
{
21+
// Arrange
22+
var db = Substitute.For<IDatabase>();
23+
var settings = new CachulaRedisCacheSettings { BatchSize = 2 };
24+
var executeCalls = 0;
25+
var createBatchCalls = 0;
26+
var batches = new List<IBatch>();
27+
28+
db.CreateBatch().Returns(ci =>
29+
{
30+
createBatchCalls++;
31+
var batch = Substitute.For<IBatch>();
32+
batches.Add(batch);
33+
34+
batch.StringSetAsync(
35+
Arg.Any<RedisKey>(),
36+
Arg.Any<RedisValue>(),
37+
Arg.Any<TimeSpan?>(),
38+
Arg.Any<When>(),
39+
Arg.Any<CommandFlags>())
40+
.Returns(Task.FromResult(true));
41+
42+
batch.When(b => b.Execute()).Do(_ => executeCalls++);
43+
44+
return batch;
45+
});
46+
47+
var cache = new CachulaRedisCache(db, settings: settings);
48+
var values = new Dictionary<string, string>
49+
{
50+
["k1"] = "v1",
51+
["k2"] = "v2",
52+
["k3"] = "v3",
53+
["k4"] = "v4",
54+
["k5"] = "v5",
55+
};
56+
57+
// Act
58+
await cache.SetManyAsync(values, TimeSpan.FromMinutes(1));
59+
60+
// Assert
61+
Assert.Multiple(() =>
62+
{
63+
// With BatchSize=2 and 5 items, we expect 3 batches (2+2+1)
64+
Assert.That(createBatchCalls, Is.EqualTo(3));
65+
Assert.That(executeCalls, Is.EqualTo(3));
66+
});
67+
68+
var stringSetCallsTotal = batches
69+
.SelectMany(b => b.ReceivedCalls())
70+
.Count(ci => ci.GetMethodInfo().Name == nameof(IBatch.StringSetAsync));
71+
Assert.That(stringSetCallsTotal, Is.EqualTo(5));
72+
}
73+
}

0 commit comments

Comments
 (0)