feat(worker,ui): wire EF Core into DI and update all consumers to IDbContextFactory

Worker and App Program.cs: replace SqliteConnectionFactory+SchemaInitializer
with AddDbContextFactory<ClaudeDoDbContext> + Database.Migrate(). Repos
changed from AddSingleton to AddScoped.

All singleton services (QueueService, StaleTaskRecovery, WorktreeManager,
TaskRunner) and singleton ViewModels (MainWindowViewModel, TaskDetailViewModel,
TaskListViewModel, TaskEditorViewModel) now take IDbContextFactory<ClaudeDoDbContext>
and create short-lived contexts per operation.

Test infrastructure: DbFixture now uses EF migrations instead of SchemaInitializer;
all test classes create contexts via DbFixture.CreateContext().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-04-16 08:59:24 +02:00
parent b7be52a623
commit 36484ed45a
18 changed files with 479 additions and 232 deletions

View File

@@ -5,6 +5,7 @@ using ClaudeDo.Worker.Config;
using ClaudeDo.Worker.Hub;
using ClaudeDo.Worker.Runner;
using ClaudeDo.Worker.Services;
using Microsoft.EntityFrameworkCore;
var cfg = WorkerConfig.Load();
@@ -14,18 +15,18 @@ var builder = WebApplication.CreateBuilder(args);
// doesn't think we crashed (~30s timeout). No-op when running interactively.
builder.Host.UseWindowsService(o => o.ServiceName = "ClaudeDoWorker");
// Initialize DB schema before the host starts accepting connections.
var dbFactory = new SqliteConnectionFactory(cfg.DbPath);
SchemaInitializer.Apply(dbFactory);
builder.Services.AddDbContextFactory<ClaudeDoDbContext>(opt =>
opt.UseSqlite($"Data Source={cfg.DbPath}"));
builder.Services.AddDbContext<ClaudeDoDbContext>(opt =>
opt.UseSqlite($"Data Source={cfg.DbPath}"));
builder.Services.AddSingleton(cfg);
builder.Services.AddSingleton(dbFactory);
builder.Services.AddSingleton<TagRepository>();
builder.Services.AddSingleton<ListRepository>();
builder.Services.AddSingleton<TaskRepository>();
builder.Services.AddSingleton<SubtaskRepository>();
builder.Services.AddSingleton<WorktreeRepository>();
builder.Services.AddSingleton<TaskRunRepository>();
builder.Services.AddScoped<TagRepository>();
builder.Services.AddScoped<ListRepository>();
builder.Services.AddScoped<TaskRepository>();
builder.Services.AddScoped<SubtaskRepository>();
builder.Services.AddScoped<WorktreeRepository>();
builder.Services.AddScoped<TaskRunRepository>();
builder.Services.AddHostedService<StaleTaskRecovery>();
builder.Services.AddSignalR();
@@ -51,6 +52,11 @@ builder.WebHost.UseUrls($"http://127.0.0.1:{cfg.SignalRPort}");
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
scope.ServiceProvider.GetRequiredService<ClaudeDoDbContext>().Database.Migrate();
}
app.MapHub<WorkerHub>("/hub");
app.Logger.LogInformation("ClaudeDo.Worker listening on http://127.0.0.1:{Port} (db: {Db})",