Make SimpleFIN split migration run only once
Track completion in a `data_migrations` table. On startup the migration checks if it has already been applied and skips the SimpleFIN API calls entirely, avoiding the slow startup. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,13 +10,28 @@ namespace Purrse.Api.Services;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// One-time data migration that splits SimpleFIN connections containing accounts
|
/// One-time data migration that splits SimpleFIN connections containing accounts
|
||||||
/// from multiple institutions into separate connections per institution.
|
/// from multiple institutions into separate connections per institution.
|
||||||
|
/// Tracks completion in a `data_migrations` table so it only runs once.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class SimpleFinConnectionMigration
|
public static class SimpleFinConnectionMigration
|
||||||
{
|
{
|
||||||
|
private const string MigrationName = "SplitSimpleFinConnectionsByInstitution";
|
||||||
|
|
||||||
public static async Task RunAsync(IServiceProvider services, ILogger logger)
|
public static async Task RunAsync(IServiceProvider services, ILogger logger)
|
||||||
{
|
{
|
||||||
using var scope = services.CreateScope();
|
using var scope = services.CreateScope();
|
||||||
var db = scope.ServiceProvider.GetRequiredService<PurrseDbContext>();
|
var db = scope.ServiceProvider.GetRequiredService<PurrseDbContext>();
|
||||||
|
|
||||||
|
// Create tracking table if it doesn't exist, then check if already applied
|
||||||
|
await db.Database.ExecuteSqlRawAsync(
|
||||||
|
"CREATE TABLE IF NOT EXISTS data_migrations (name TEXT PRIMARY KEY, applied_at TIMESTAMP NOT NULL)");
|
||||||
|
|
||||||
|
var alreadyApplied = await db.Database
|
||||||
|
.SqlQueryRaw<int>($"SELECT 1 AS \"Value\" FROM data_migrations WHERE name = '{MigrationName}'")
|
||||||
|
.AnyAsync();
|
||||||
|
|
||||||
|
if (alreadyApplied)
|
||||||
|
return;
|
||||||
|
|
||||||
var encryption = scope.ServiceProvider.GetRequiredService<IEncryptionService>();
|
var encryption = scope.ServiceProvider.GetRequiredService<IEncryptionService>();
|
||||||
var simpleFin = scope.ServiceProvider.GetRequiredService<SimpleFinSyncProvider>();
|
var simpleFin = scope.ServiceProvider.GetRequiredService<SimpleFinSyncProvider>();
|
||||||
|
|
||||||
@@ -26,7 +41,10 @@ public static class SimpleFinConnectionMigration
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
if (connections.Count == 0)
|
if (connections.Count == 0)
|
||||||
|
{
|
||||||
|
await MarkCompleteAsync(db);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var splitCount = 0;
|
var splitCount = 0;
|
||||||
|
|
||||||
@@ -113,5 +131,13 @@ public static class SimpleFinConnectionMigration
|
|||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
logger.LogInformation("SimpleFIN connection migration complete: created {Count} new connections", splitCount);
|
logger.LogInformation("SimpleFIN connection migration complete: created {Count} new connections", splitCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await MarkCompleteAsync(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task MarkCompleteAsync(PurrseDbContext db)
|
||||||
|
{
|
||||||
|
await db.Database.ExecuteSqlRawAsync(
|
||||||
|
$"INSERT INTO data_migrations (name, applied_at) VALUES ('{MigrationName}', NOW()) ON CONFLICT DO NOTHING");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user