Skip to content

Commit 1027240

Browse files
Add a license status check to ensure the RavenDB license is correctly applied after the database is created before configuring expiration (#5235)
* Add a license status check to ensure the RavenDB licence is correctly applied after the database is created before configuring expiration * record type * Using `/` would override BaseAddress path value * ReadFromJsonAsync * fix * As we are not re-using HttpClient it can be immediately disposed * Forward cancellation token * Improve license validation logic and exception handling - Refactored license check to use `CancellationTokenSource` for a more robust timeout mechanism. - Simplified loop logic by removing redundant variables. - Replaced `NotSupportedException` with `InvalidOperationException` for better error clarity. * Add a comment for posterity --------- Co-authored-by: Ramon Smits <[email protected]>
1 parent c21d63c commit 1027240

File tree

4 files changed

+86
-0
lines changed

4 files changed

+86
-0
lines changed

src/ServiceControl.Audit.Persistence.RavenDB/DatabaseSetup.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
using System;
44
using System.Collections.Generic;
5+
using System.Net.Http;
6+
using System.Text.Json;
57
using System.Threading;
68
using System.Threading.Tasks;
79
using Raven.Client.Documents;
@@ -25,6 +27,7 @@ public async Task Execute(IDocumentStore documentStore, CancellationToken cancel
2527

2628
await CreateIndexes(documentStore, configuration.EnableFullTextSearch, cancellationToken);
2729

30+
await LicenseStatusCheck.WaitForLicenseOrThrow(configuration, cancellationToken);
2831
await ConfigureExpiration(documentStore, cancellationToken);
2932
}
3033

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
namespace ServiceControl.Audit.Persistence.RavenDB;
2+
3+
using System;
4+
using System.Net.Http;
5+
using System.Net.Http.Json;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
9+
static class LicenseStatusCheck
10+
{
11+
record LicenseStatusFragment(string Id, string LicensedTo, string Status, bool Expired);
12+
13+
public static async Task WaitForLicenseOrThrow(DatabaseConfiguration configuration, CancellationToken cancellationToken)
14+
{
15+
using var client = new HttpClient
16+
{
17+
BaseAddress = new Uri(configuration.ServerConfiguration.ConnectionString ?? configuration.ServerConfiguration.ServerUrl)
18+
};
19+
20+
// Not linking to the incoming cancellationToken to ensure no OperationCancelledException prevents the last InvalidOperationException to be thrown
21+
using var cts = new CancellationTokenSource(30_000);
22+
while (!cts.IsCancellationRequested)
23+
{
24+
var httpResponse = await client.GetAsync("license/status", cancellationToken);
25+
var licenseStatus = await httpResponse.Content.ReadFromJsonAsync<LicenseStatusFragment>(cancellationToken);
26+
if (licenseStatus.Expired)
27+
{
28+
throw new InvalidOperationException("The current RavenDB license is expired. Please, contact support");
29+
}
30+
31+
if (licenseStatus.LicensedTo != null && licenseStatus.Id != null)
32+
{
33+
return;
34+
}
35+
36+
await Task.Delay(200, cancellationToken);
37+
}
38+
39+
throw new InvalidOperationException("Cannot validate the current RavenDB license. Please, contact support");
40+
}
41+
}

src/ServiceControl.Persistence.RavenDB/DatabaseSetup.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public async Task Execute(CancellationToken cancellationToken)
2323

2424
await IndexCreation.CreateIndexesAsync(typeof(DatabaseSetup).Assembly, documentStore, null, null, cancellationToken);
2525

26+
await LicenseStatusCheck.WaitForLicenseOrThrow(settings, cancellationToken);
2627
await ConfigureExpiration(settings, cancellationToken);
2728
}
2829

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
namespace ServiceControl.Persistence.RavenDB;
2+
3+
using System;
4+
using System.Net.Http;
5+
using System.Net.Http.Json;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
9+
static class LicenseStatusCheck
10+
{
11+
record LicenseStatusFragment(string Id, string LicensedTo, string Status, bool Expired);
12+
13+
public static async Task WaitForLicenseOrThrow(RavenPersisterSettings configuration, CancellationToken cancellationToken)
14+
{
15+
using var client = new HttpClient
16+
{
17+
BaseAddress = new Uri(configuration.ConnectionString ?? configuration.ServerUrl)
18+
};
19+
20+
// Not linking to the incoming cancellationToken to ensure no OperationCancelledException prevents the last InvalidOperationException to be thrown
21+
using var cts = new CancellationTokenSource(30_000);
22+
while (!cts.IsCancellationRequested)
23+
{
24+
var httpResponse = await client.GetAsync("license/status", cancellationToken);
25+
var licenseStatus = await httpResponse.Content.ReadFromJsonAsync<LicenseStatusFragment>(cancellationToken);
26+
if (licenseStatus.Expired)
27+
{
28+
throw new InvalidOperationException("The current RavenDB license is expired. Please, contact support");
29+
}
30+
31+
if (licenseStatus.LicensedTo != null && licenseStatus.Id != null)
32+
{
33+
return;
34+
}
35+
36+
await Task.Delay(200, cancellationToken);
37+
}
38+
39+
throw new InvalidOperationException("Cannot validate the current RavenDB license. Please, contact support");
40+
}
41+
}

0 commit comments

Comments
 (0)