mirror of
https://github.com/MAKS-IT-COM/maksit-certs-ui.git
synced 2026-05-16 04:48:12 +02:00
(bugfix): fixed fluent migrator startup order
This commit is contained in:
parent
d8cb164de9
commit
8a3e42a159
@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [3.3.9] - 2026-04-26
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Startup / database:** FluentMigrator (`EnsureCertsEngineMigratedAsync`) now runs in `Program.cs` immediately after `WebApplication.Build()` and before `RunAsync`, so schema (including `app_runtime_leases`) exists before any `IHostedService` starts. `InitializationHostedService` only performs bootstrap lease + identity init.
|
||||||
|
|
||||||
## [3.3.8] - 2026-04-26
|
## [3.3.8] - 2026-04-26
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@ -4,11 +4,11 @@ using Microsoft.Extensions.Hosting;
|
|||||||
namespace MaksIT.CertsUI.Engine.Extensions;
|
namespace MaksIT.CertsUI.Engine.Extensions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DB migrations are handled by FluentMigrator and optional schema sync from InitializationHostedService.
|
/// DB migrations run in <c>Program.cs</c> via <see cref="ServiceCollectionExtensions.EnsureCertsEngineMigratedAsync"/> before <c>RunAsync</c>.
|
||||||
/// This method is a no-op for backward compatibility with host startup.
|
/// This method is a no-op kept for backward compatibility with older host wiring.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ApplicationBuilderExtensions {
|
public static class ApplicationBuilderExtensions {
|
||||||
public static void AddCertsEngineMigrations(this IHost host) {
|
public static void AddCertsEngineMigrations(this IHost host) {
|
||||||
// No-op: migrations and schema sync run from InitializationHostedService via IRunMigrationsService and ISchemaSyncService.
|
// No-op: see Program.cs (migrations) and InitializationHostedService (identity bootstrap under lease).
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,7 +67,7 @@ public static class ServiceCollectionExtensions {
|
|||||||
#region Host initialization helpers
|
#region Host initialization helpers
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs FluentMigrator then optional add-only schema sync (when <see cref="ICertsEngineConfiguration.AutoSyncSchema"/> is true). Called from host startup (e.g. InitializationHostedService).
|
/// Runs FluentMigrator then optional add-only schema sync (when <see cref="ICertsEngineConfiguration.AutoSyncSchema"/> is true). Called from <c>Program.cs</c> before <c>RunAsync</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static async Task EnsureCertsEngineMigratedAsync(this IServiceProvider serviceProvider) {
|
public static async Task EnsureCertsEngineMigratedAsync(this IServiceProvider serviceProvider) {
|
||||||
await using var scope = serviceProvider.CreateAsyncScope();
|
await using var scope = serviceProvider.CreateAsyncScope();
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using MaksIT.CertsUI.Engine.DomainServices;
|
using MaksIT.CertsUI.Engine.DomainServices;
|
||||||
using MaksIT.CertsUI.Engine.Extensions;
|
|
||||||
using MaksIT.CertsUI.Engine.Infrastructure;
|
using MaksIT.CertsUI.Engine.Infrastructure;
|
||||||
using MaksIT.CertsUI.Engine.RuntimeCoordination;
|
using MaksIT.CertsUI.Engine.RuntimeCoordination;
|
||||||
|
|
||||||
namespace MaksIT.CertsUI.HostedServices;
|
namespace MaksIT.CertsUI.HostedServices;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs startup initialization (migrations + identity bootstrap) before the API starts serving requests.
|
/// Runs identity bootstrap before the API starts serving requests. FluentMigrator already ran in <c>Program.cs</c>
|
||||||
/// FluentMigrator runs first on every instance (same pattern as Vault); the bootstrap lease then ensures
|
/// before the host starts. The bootstrap lease ensures only one replica writes against shared
|
||||||
/// only one replica performs identity bootstrap against shared <see cref="Configuration.CertsUIEngineConfiguration.DataFolder"/>.
|
/// <see cref="Configuration.CertsUIEngineConfiguration.DataFolder"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class InitializationHostedService(
|
public sealed class InitializationHostedService(
|
||||||
ILogger<InitializationHostedService> logger,
|
ILogger<InitializationHostedService> logger,
|
||||||
@ -23,18 +22,11 @@ public sealed class InitializationHostedService(
|
|||||||
|
|
||||||
public async Task StartAsync(CancellationToken cancellationToken) {
|
public async Task StartAsync(CancellationToken cancellationToken) {
|
||||||
const int delayMilliseconds = 2000;
|
const int delayMilliseconds = 2000;
|
||||||
var migrationsApplied = false;
|
|
||||||
|
|
||||||
while (!cancellationToken.IsCancellationRequested) {
|
while (!cancellationToken.IsCancellationRequested) {
|
||||||
try {
|
try {
|
||||||
logger.LogInformation("Running startup initialization...");
|
logger.LogInformation("Running startup initialization...");
|
||||||
|
|
||||||
// Migrations must run before lease acquisition: app_runtime_leases is created by FluentMigrator.
|
|
||||||
if (!migrationsApplied) {
|
|
||||||
await serviceProvider.EnsureCertsEngineMigratedAsync().ConfigureAwait(false);
|
|
||||||
migrationsApplied = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var holder = runtimeInstance.InstanceId;
|
var holder = runtimeInstance.InstanceId;
|
||||||
var acquired = await runtimeLease.TryAcquireAsync(RuntimeLeaseNames.Bootstrap, holder, BootstrapLeaseTtl, cancellationToken).ConfigureAwait(false);
|
var acquired = await runtimeLease.TryAcquireAsync(RuntimeLeaseNames.Bootstrap, holder, BootstrapLeaseTtl, cancellationToken).ConfigureAwait(false);
|
||||||
if (!acquired.IsSuccess)
|
if (!acquired.IsSuccess)
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>3.3.8</Version>
|
<Version>3.3.9</Version>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
|||||||
@ -135,6 +135,9 @@ builder.Services.AddHealthChecks()
|
|||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// FluentMigrator must complete before any IHostedService starts; bootstrap lease uses app_runtime_leases.
|
||||||
|
await app.Services.EnsureCertsEngineMigratedAsync();
|
||||||
|
|
||||||
app.UseMiddleware<ErrorHandlingMiddleware>();
|
app.UseMiddleware<ErrorHandlingMiddleware>();
|
||||||
|
|
||||||
app.AddCertsEngineMigrations();
|
app.AddCertsEngineMigrations();
|
||||||
@ -169,4 +172,4 @@ app.MapGet("/health/ready", async (CancellationToken ct) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.Run();
|
await app.RunAsync();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user