Skip to content

Commit 1a5b99a

Browse files
authored
Updated packages (#229)
1 parent 7d89914 commit 1a5b99a

9 files changed

Lines changed: 91 additions & 63 deletions

File tree

scripts/assign-roles.sh

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
SUBSCRIPTION_ID="c0c21e76-a03c-4747-af34-0720b273ff00"
1919
RESOURCE_GROUP="rg-xenobiasoft-sudoku-prod-westus2"
2020

21+
DEVELOPER_OID="79d81279-ad74-4496-a1bc-32636c40c0e3"
22+
2123
WEB_APP_NAME="XenobiasoftSudoku-prod"
2224
API_APP_NAME="XenobiasoftSudokuApi-prod"
2325

@@ -82,21 +84,24 @@ assign_cosmos_role() {
8284
echo "---------------------------------------------------------------------"
8385
echo "Key Vault — Secrets User (read-only)"
8486
echo "---------------------------------------------------------------------"
85-
assign_role "Blazor → Key Vault" "$WEB_APP_PRINCIPAL" "$KEY_VAULT_SECRETS_USER" "$KEY_VAULT_ID"
86-
assign_role "API → Key Vault" "$API_APP_PRINCIPAL" "$KEY_VAULT_SECRETS_USER" "$KEY_VAULT_ID"
87+
assign_role "Blazor → Key Vault" "$WEB_APP_PRINCIPAL" "$KEY_VAULT_SECRETS_USER" "$KEY_VAULT_ID"
88+
assign_role "API → Key Vault" "$API_APP_PRINCIPAL" "$KEY_VAULT_SECRETS_USER" "$KEY_VAULT_ID"
89+
assign_role "DevEng → Key Vault" "$DEVELOPER_OID" "$KEY_VAULT_SECRETS_USER" "$KEY_VAULT_ID"
8790

8891
echo ""
8992
echo "---------------------------------------------------------------------"
9093
echo "App Configuration — Data Reader"
9194
echo "---------------------------------------------------------------------"
92-
assign_role "Blazor → App Config" "$WEB_APP_PRINCIPAL" "$APP_CONFIG_DATA_READER" "$APP_CONFIG_ID"
93-
assign_role "API → App Config" "$API_APP_PRINCIPAL" "$APP_CONFIG_DATA_READER" "$APP_CONFIG_ID"
95+
assign_role "Blazor → App Config" "$WEB_APP_PRINCIPAL" "$APP_CONFIG_DATA_READER" "$APP_CONFIG_ID"
96+
assign_role "API → App Config" "$API_APP_PRINCIPAL" "$APP_CONFIG_DATA_READER" "$APP_CONFIG_ID"
97+
assign_role "DevEng → App Config" "$DEVELOPER_OID" "$APP_CONFIG_DATA_READER" "$APP_CONFIG_ID"
9498

9599
echo ""
96100
echo "---------------------------------------------------------------------"
97101
echo "Cosmos DB — Built-in Data Contributor (API only)"
98102
echo "---------------------------------------------------------------------"
99-
assign_cosmos_role "API → Cosmos DB" "$API_APP_PRINCIPAL"
103+
assign_cosmos_role "API → Cosmos DB" "$API_APP_PRINCIPAL"
104+
assign_cosmos_role "DevEng → Cosmos DB" "$DEVELOPER_OID"
100105

101106
echo ""
102107
echo "Done! All role assignments are in place for '$RESOURCE_GROUP'."

src/backend/Sudoku.Api/Sudoku.Api.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<PackageReference Include="Aspire.Azure.Security.KeyVault" Version="13.2.2" />
1414
<PackageReference Include="Aspire.Microsoft.Azure.Cosmos" Version="13.2.2" />
1515
<PackageReference Include="MediatR" Version="14.1.0" />
16-
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.5" />
16+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.6" />
1717
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.7" />
1818
</ItemGroup>
1919

src/backend/Sudoku.Api/appsettings.Development.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
}
77
},
88
"CosmosDb": {
9-
"ContainerName": "games-dev"
9+
"DatabaseName": "sudoku-dev"
1010
},
1111
"appconfig": {
1212
"Endpoint": "https://appcs-xenobiasoft-prod.azconfig.io",

src/backend/Sudoku.Infrastructure/Services/CosmosDbService.cs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,6 @@ private async Task EnsureDatabaseExistsAsync()
167167
try
168168
{
169169
await InitializeCosmosDbAsync();
170-
171-
var database = cosmosClient.GetDatabase(_options.DatabaseName);
172-
_container = database.GetContainer(_options.ContainerName);
173170
}
174171
catch (Exception ex)
175172
{
@@ -180,16 +177,42 @@ private async Task EnsureDatabaseExistsAsync()
180177

181178
private async Task InitializeCosmosDbAsync()
182179
{
183-
logger.LogInformation("Ensuring CosmosDB database and container exist at endpoint URI: {Endpoint}", cosmosClient.Endpoint);
180+
logger.LogInformation("Verifying CosmosDB database and container exist at endpoint URI: {Endpoint}", cosmosClient.Endpoint);
181+
182+
var database = cosmosClient.GetDatabase(_options.DatabaseName);
184183

185-
var database = await cosmosClient.CreateDatabaseIfNotExistsAsync(_options.DatabaseName, throughput: 400);
184+
try
185+
{
186+
await database.ReadAsync();
187+
}
188+
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
189+
{
190+
throw new InvalidOperationException($"CosmosDB database '{_options.DatabaseName}' does not exist.", ex);
191+
}
192+
catch (CosmosException ex)
193+
{
194+
throw new InvalidOperationException($"Failed to access CosmosDB database '{_options.DatabaseName}'. Status: {ex.StatusCode}", ex);
195+
}
186196

187-
logger.LogInformation("Database {DatabaseName} ensured", _options.DatabaseName);
197+
logger.LogInformation("Database {DatabaseName} verified", _options.DatabaseName);
188198

189-
var containerProperties = new ContainerProperties(id: _options.ContainerName, partitionKeyPath: "/gameId");
199+
var container = database.GetContainer(_options.ContainerName);
200+
201+
try
202+
{
203+
await container.ReadContainerAsync();
204+
}
205+
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
206+
{
207+
throw new InvalidOperationException($"CosmosDB container '{_options.ContainerName}' does not exist in database '{_options.DatabaseName}'.", ex);
208+
}
209+
catch (CosmosException ex)
210+
{
211+
throw new InvalidOperationException($"Failed to access CosmosDB container '{_options.ContainerName}'. Status: {ex.StatusCode}", ex);
212+
}
190213

191-
await database.Database.CreateContainerIfNotExistsAsync(containerProperties);
214+
logger.LogInformation("Container {ContainerName} verified", _options.ContainerName);
192215

193-
logger.LogInformation("Container {ContainerName} ensured", _options.ContainerName);
216+
_container = container;
194217
}
195218
}

src/backend/Sudoku.Infrastructure/Sudoku.Infrastructure.csproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@
1515

1616
<ItemGroup>
1717
<PackageReference Include="Aspire.Microsoft.Azure.Cosmos" Version="13.2.2" />
18-
<PackageReference Include="Azure.Identity" Version="1.19.0" />
18+
<PackageReference Include="Azure.Identity" Version="1.21.0" />
1919
<PackageReference Include="Azure.Storage.Blobs" Version="12.27.0" />
2020
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.58.0" />
2121
<PackageReference Include="Microsoft.Extensions.Azure" Version="1.13.1" />
22-
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.5" />
23-
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.5" />
24-
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.5" />
25-
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.5" />
22+
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.6" />
23+
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.6" />
24+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.6" />
25+
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.6" />
2626
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
27-
<PackageReference Include="System.Text.Json" Version="10.0.5" />
27+
<PackageReference Include="System.Text.Json" Version="10.0.6" />
2828
</ItemGroup>
2929

3030
</Project>

src/backend/Sudoku.ServiceDefaults/Sudoku.ServiceDefaults.csproj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@
1111
<FrameworkReference Include="Microsoft.AspNetCore.App" />
1212
<PackageReference Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.4.0" />
1313

14-
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="10.4.0" />
15-
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="10.4.0" />
16-
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.1" />
17-
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.1" />
14+
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="10.5.0" />
15+
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="10.5.0" />
16+
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.2" />
17+
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.2" />
1818
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.1" />
1919
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.15.0" />
2020
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.0" />
2121
<PackageReference Include="Microsoft.Extensions.Configuration.AzureAppConfiguration" Version="8.5.0" />
22-
<PackageReference Include="Azure.Identity" Version="1.19.0" />
22+
<PackageReference Include="Azure.Identity" Version="1.21.0" />
2323
</ItemGroup>
2424

2525
</Project>

src/backend/Tests/UnitTests.csproj

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@
1111
<ItemGroup>
1212
<PackageReference Include="AutoFixture" Version="4.18.1" />
1313
<PackageReference Include="AutoFixture.AutoMoq" Version="4.18.1" />
14-
<PackageReference Include="bunit" Version="2.6.2" />
14+
<PackageReference Include="bunit" Version="2.7.2" />
1515
<PackageReference Include="DepenMock.XUnit.V3" Version="1.2.1" />
1616
<PackageReference Include="FluentAssertions" Version="8.9.0" />
17-
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.5" />
18-
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.5" />
19-
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.5" />
20-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
17+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.6" />
18+
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.6" />
19+
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.6" />
20+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.4.0" />
2121
<PackageReference Include="Moq" Version="4.20.72" />
22-
<PackageReference Include="System.Linq.Async" Version="7.0.0" />
22+
<PackageReference Include="System.Linq.Async" Version="7.0.1" />
2323
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
2424
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2525
<PrivateAssets>all</PrivateAssets>
2626
</PackageReference>
27-
<PackageReference Include="coverlet.collector" Version="8.0.1">
27+
<PackageReference Include="coverlet.collector" Version="10.0.0">
2828
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2929
<PrivateAssets>all</PrivateAssets>
3030
</PackageReference>

src/frontend/Sudoku.Blazor/ServiceCollectionExtensionMethods.cs

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Sudoku.Blazor.Services;
1+
using Microsoft.Extensions.Http.Resilience;
2+
using Sudoku.Blazor.Services;
23
using Sudoku.Blazor.Services.Abstractions;
34
using Sudoku.Blazor.Services.HttpClients;
45

@@ -19,38 +20,37 @@ public static IServiceCollection RegisterBlazorGameServices(this IServiceCollect
1920
.AddScoped<IGameTimer>(sp => new GameTimer(TimeSpan.FromSeconds(1)));
2021

2122
var apiBaseUrl = config["ApiBaseUrl"];
22-
23+
24+
// Shared resilience configuration for all API clients.
25+
// Tweak these values while testing to find the right balance.
26+
static void ConfigureResilience(HttpStandardResilienceOptions options)
27+
{
28+
// Per-attempt timeout.
29+
options.AttemptTimeout.Timeout = TimeSpan.FromSeconds(20);
30+
31+
// 0 retries = 1 total attempt. Bump this as needed while testing.
32+
options.Retry.MaxRetryAttempts = 1;
33+
34+
// TotalRequestTimeout must be strictly greater than AttemptTimeout.
35+
// Keep it at least AttemptTimeout * (MaxRetryAttempts + 1) + a small buffer.
36+
options.TotalRequestTimeout.Timeout = TimeSpan.FromSeconds(25);
37+
38+
// CircuitBreaker.SamplingDuration must be >= 2 * AttemptTimeout.
39+
options.CircuitBreaker.SamplingDuration = TimeSpan.FromSeconds(60);
40+
}
41+
2342
services.AddHttpClient<IGameApiClient, GameApiClient>(client =>
2443
{
2544
client.BaseAddress = new Uri(apiBaseUrl);
2645
})
27-
.AddStandardResilienceHandler(options =>
28-
{
29-
// Configure retry policy to only retry idempotent methods (GET, HEAD, OPTIONS, etc.)
30-
options.Retry.ShouldHandle = args =>
31-
{
32-
// Only retry for GET requests
33-
if (args.Outcome.Result?.RequestMessage?.Method == HttpMethod.Get)
34-
{
35-
return ValueTask.FromResult(args.Outcome.Result.StatusCode >= System.Net.HttpStatusCode.InternalServerError);
36-
}
37-
38-
// Don't retry POST, PUT, DELETE, PATCH
39-
return ValueTask.FromResult(false);
40-
};
41-
42-
// Reduce max retry attempts
43-
options.Retry.MaxRetryAttempts = 2;
44-
options.Retry.Delay = TimeSpan.FromMilliseconds(500);
45-
});
46-
47-
// Configure HttpClient for PlayerApiClient with the same logic
46+
.AddStandardResilienceHandler(ConfigureResilience);
47+
4848
services.AddHttpClient<IPlayerApiClient, PlayerApiClient>(client =>
4949
{
5050
client.BaseAddress = new Uri(apiBaseUrl);
5151
})
52-
.AddStandardResilienceHandler();
53-
52+
.AddStandardResilienceHandler(ConfigureResilience);
53+
5454
return services;
5555
}
5656
}

src/frontend/Sudoku.Blazor/Sudoku.Blazor.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
<PackageReference Include="Aspire.Microsoft.Azure.Cosmos" Version="13.2.2" />
1313
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.5.0" />
1414
<PackageReference Include="BlazorApplicationInsights" Version="3.3.0" />
15-
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0" />
15+
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="3.1.0" />
1616
<PackageReference Include="Microsoft.Extensions.Azure" Version="1.13.1" />
17-
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.5" />
18-
<PackageReference Include="Microsoft.Extensions.Logging.ApplicationInsights" Version="2.22.0" />
19-
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="10.0.5" />
17+
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.6" />
18+
<PackageReference Include="Microsoft.Extensions.Logging.ApplicationInsights" Version="2.23.0" />
19+
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="10.0.6" />
2020
</ItemGroup>
2121

2222
<ItemGroup>

0 commit comments

Comments
 (0)