The target Pi only has MariaDB, and SQL Server has no ARM64 build at all - not a config problem, a real gap discovered during deployment setup. Swapped the EF Core provider, regenerated every migration, updated connection strings and the backup script everywhere they appear. Took two tries to land on a provider that actually works: Pomelo builds fine against this project's EF Core 10 packages but fails at runtime (it's compiled against 9's internal API surface, which moved in 10 wherever Identity/DataProtection force the newer packages). Oracle's official provider builds and migrates fine but has a real MariaDB bug in its own migration-lock code, reproduced against a live database. Kept Oracle's provider and worked around just that one broken method - everything else it does is correct - rather than give up more of the stack to chase a workaround. Verified against a real local MariaDB end to end: all three migrations applied, both hosts start clean, full suite still green.
71 lines
2.9 KiB
C#
71 lines
2.9 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Migrations;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Http.Resilience;
|
|
using Polly;
|
|
using SlpModularCms.Core.Hosting;
|
|
using SlpModularCms.Core.Modules;
|
|
using SlpModularCms.Modules.Master.BackgroundServices;
|
|
using SlpModularCms.Modules.Master.Data;
|
|
using SlpModularCms.Modules.Master.Config;
|
|
using SlpModularCms.Modules.Master.Repositories;
|
|
using SlpModularCms.Modules.Master.Services;
|
|
|
|
namespace SlpModularCms.Modules.Master;
|
|
|
|
[ExcludeFromCodeCoverage]
|
|
public class MasterModule : IModule
|
|
{
|
|
public string Name => "Master";
|
|
public string Version => "1.0.0";
|
|
|
|
public void RegisterServices(IServiceCollection services)
|
|
{
|
|
// Data Protection is configured once by the host (AddCmsDataProtection), NOT here.
|
|
// See the equivalent note in AvailabilityModule: a bare AddDataProtection() call here
|
|
// would override the host's persistent key store, and the resulting defect is invisible
|
|
// until the first release switch makes every stored slave API key undecryptable.
|
|
services.AddSingleton<IApiKeyProtector, ApiKeyProtector>();
|
|
|
|
services.AddOptions<MasterModuleOptions>().BindConfiguration("MasterModule");
|
|
|
|
services.AddDbContext<MasterDbContext>((serviceProvider, options) =>
|
|
{
|
|
var config = serviceProvider.GetRequiredService<IConfiguration>();
|
|
options.UseMySQL(config.GetConnectionString("DefaultConnection")!);
|
|
options.ReplaceService<IHistoryRepository, NonLockingMySQLHistoryRepository>();
|
|
});
|
|
|
|
services.AddScoped<ICmsInstanceRepository, CmsInstanceRepository>();
|
|
services.AddScoped<MasterServiceDependencies>();
|
|
services.AddScoped<ICmsInstanceService, CmsInstanceService>();
|
|
|
|
services.AddHttpClient<ISlaveApiClient, SlaveApiClient>()
|
|
.AddResilienceHandler("slave-resilience", (builder, context) =>
|
|
{
|
|
var opts = context.ServiceProvider.GetRequiredService<Microsoft.Extensions.Options.IOptions<MasterModuleOptions>>();
|
|
builder.AddRetry(new HttpRetryStrategyOptions
|
|
{
|
|
MaxRetryAttempts = 2,
|
|
Delay = TimeSpan.FromSeconds(1),
|
|
BackoffType = DelayBackoffType.Exponential,
|
|
UseJitter = true
|
|
});
|
|
builder.AddTimeout(TimeSpan.FromSeconds(opts.Value.HttpTimeoutSeconds));
|
|
});
|
|
|
|
services.AddHostedService<IntegrityCheckBackgroundService>();
|
|
services.AddHttpContextAccessor();
|
|
}
|
|
|
|
public void UseModule(IApplicationBuilder app)
|
|
{
|
|
using var scope = app.ApplicationServices.CreateScope();
|
|
var db = scope.ServiceProvider.GetRequiredService<MasterDbContext>();
|
|
db.Database.Migrate();
|
|
}
|
|
}
|