Skip to content

Commit 15b5f4c

Browse files
Implemented change tracking
1 parent 103225d commit 15b5f4c

4 files changed

Lines changed: 97 additions & 7 deletions

File tree

src/Config.SqlStreamStore.Tests/StreamStoreConfigurationProviderTests.cs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Threading;
34
using System.Threading.Tasks;
45
using Microsoft.Extensions.Configuration;
6+
using Microsoft.Extensions.Primitives;
57
using SqlStreamStore;
68
using Xunit;
79

@@ -91,16 +93,51 @@ IStreamStore FakeStreamStoreFactory(string providedConnectionString)
9193
[Fact]
9294
public async Task Can_reload_when_data_chagnes()
9395
{
96+
// Create a SSS instance with some settings
9497
var instance = await BuildSteamStoreWithSettings(("setting1", "value1"));
9598

9699
var config = new ConfigurationBuilder()
97-
.Add(new StreamStoreConfigurationSource(() => instance))
100+
.Add(new StreamStoreConfigurationSource(() => instance)
101+
{
102+
SubscribeToChanges = true
103+
})
104+
.Build();
105+
106+
await new ConfigRepository(instance).Modify(CancellationToken.None,
107+
("setting1", "modified"));
108+
109+
await WaitUntil(() => config["setting1"] == "modified");
110+
111+
Assert.Equal("modified", config["setting1"]);
112+
113+
}
114+
115+
[Fact]
116+
public async Task Triggers_reload_token_on_change()
117+
{
118+
// Create a SSS instance with some settings
119+
var instance = await BuildSteamStoreWithSettings(("setting1", "value1"));
120+
121+
var config = new ConfigurationBuilder()
122+
.Add(new StreamStoreConfigurationSource(() => instance)
123+
{
124+
SubscribeToChanges = true
125+
})
98126
.Build();
99127

128+
var tcs = new TaskCompletionSource<bool>();
129+
ChangeToken.OnChange(config.GetReloadToken, () => tcs.SetResult(true));
130+
131+
await new ConfigRepository(instance).Modify(CancellationToken.None,
132+
("setting1", "modified"));
100133

134+
var noftifiedSettings = await Task.WhenAny(tcs.Task, Task.Delay(TimeSpan.FromSeconds(1)));
101135

136+
Assert.True(tcs.Task.IsCompleted);
137+
Assert.Equal("modified", config["setting1"]);
102138
}
103139

140+
104141
private static async Task<InMemoryStreamStore> BuildSteamStoreWithSettings(params (string key, string value)[] settings)
105142
{
106143
var instance = new InMemoryStreamStore();
@@ -111,5 +148,15 @@ await repo.WriteChanges(new ModifiedConfigurationSettings(
111148

112149
return instance;
113150
}
151+
152+
private async Task WaitUntil(Func<bool> isTrue, TimeSpan? timeout = null)
153+
{
154+
var actualTimeout = timeout ?? TimeSpan.FromSeconds(1);
155+
for (int i = 0; i < actualTimeout.TotalMilliseconds / 10; i++)
156+
{
157+
if(isTrue()) break;
158+
await Task.Delay(10);
159+
}
160+
}
114161
}
115162
}

src/Config.SqlStreamStore/ConfigRepository.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ namespace Config.SqlStreamStore
1212
public interface IConfigRepository
1313
{
1414
Task<ConfigurationSettings> GetLatest(CancellationToken ct);
15+
Task<IConfigurationSettings> WriteChanges(IConfigurationSettings settings, CancellationToken ct);
16+
17+
IDisposable SubscribeToChanges(int version,
18+
ConfigRepository.OnSettingsChanged onSettingsChanged,
19+
CancellationToken ct);
1520
}
1621

1722
public class ConfigRepository : IConfigRepository
@@ -54,6 +59,15 @@ private static async Task<ConfigurationSettings> BuildConfigurationSettingsFromM
5459
return new ConfigurationSettings(message.StreamVersion, message.CreatedUtc, configChanged.AllSettings);
5560
}
5661

62+
public async Task<IConfigurationSettings> Modify(CancellationToken ct,
63+
params (string Key, string Value)[] modifications)
64+
{
65+
var currentData = await GetLatest(ct);
66+
var modified = currentData.Modify(modifications);
67+
return await WriteChanges(modified, ct);
68+
}
69+
70+
5771
public async Task<IConfigurationSettings> WriteChanges(IConfigurationSettings settings, CancellationToken ct)
5872
{
5973
var changes = (settings as ModifiedConfigurationSettings)?.GetChanges();

src/Config.SqlStreamStore/StreamStoreConfigurationProvider.cs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,54 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Threading;
5+
using System.Threading.Tasks;
56
using Microsoft.Extensions.Configuration;
67
using Microsoft.Extensions.Primitives;
78

89
namespace Config.SqlStreamStore
910
{
1011
public class StreamStoreConfigurationProvider : ConfigurationProvider
1112
{
13+
private readonly StreamStoreConfigurationSource _source;
1214
private readonly IConfigRepository _configRepository;
15+
private ConfigurationSettings _configurationSettings;
1316

14-
public StreamStoreConfigurationProvider(IConfigRepository configRepository)
17+
public StreamStoreConfigurationProvider(StreamStoreConfigurationSource source,
18+
IConfigRepository configRepository)
1519
{
20+
_source = source;
1621
_configRepository = configRepository;
22+
1723
}
1824
public override void Load()
1925
{
20-
var settings = _configRepository
26+
_configurationSettings = _configRepository
2127
.GetLatest(CancellationToken.None).GetAwaiter().GetResult();
2228

29+
Data = _configurationSettings.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);
30+
31+
if (_source.SubscribeToChanges)
32+
{
33+
SubscribeToChanges(CancellationToken.None);
34+
}
35+
36+
}
37+
38+
public IDisposable SubscribeToChanges(CancellationToken ct)
39+
{
40+
return _configRepository.SubscribeToChanges(
41+
version: _configurationSettings?.Version ?? 0,
42+
onSettingsChanged: OnChanged,
43+
ct: CancellationToken.None);
44+
}
45+
46+
private Task OnChanged(ConfigurationSettings settings, CancellationToken ct)
47+
{
2348
Data = settings.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);
49+
50+
OnReload();
51+
52+
return Task.CompletedTask;
2453
}
2554
}
2655
}

src/Config.SqlStreamStore/StreamStoreConfigurationSource.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class StreamStoreConfigurationSource : IConfigurationSource
1212
public delegate IConfigRepository BuildConfigRepository();
1313
private readonly BuildStreamStoreFromConfig _buildStreamStoreFromConfig;
1414

15-
15+
public bool SubscribeToChanges { get; set; }
1616

1717
private readonly BuildConfigRepository _getConfigRepository;
1818

@@ -52,7 +52,7 @@ public IConfigurationProvider Build(IConfigurationBuilder builder)
5252
{
5353
if (_getConfigRepository != null)
5454
{
55-
return new StreamStoreConfigurationProvider(_getConfigRepository());
55+
return new StreamStoreConfigurationProvider(this, _getConfigRepository());
5656
}
5757

5858
var innerBuilder = new ConfigurationBuilder();
@@ -66,7 +66,7 @@ public IConfigurationProvider Build(IConfigurationBuilder builder)
6666

6767
var repo = new ConfigRepository(_buildStreamStoreFromConfig(innerBuilder.Build()));
6868

69-
return new StreamStoreConfigurationProvider(repo);
69+
return new StreamStoreConfigurationProvider(this, repo);
7070

7171
}
7272

0 commit comments

Comments
 (0)