Baustein 5: EventApplier (Inbound Apply) + Loop-Prevention (Kapitel 10)
Die zentrale, bisher komplett fehlende Luecke: selbst mit Baustein 1-4 haette SyncEngine.PullAsync empfangene Ereignisse nur zur Konflikterkennung genutzt, nie in die lokale LiteDB geschrieben - ankommende Aenderungen von anderen Geraeten waeren nirgends sichtbar geworden. Neu EventApplier: entschluesselt, dispatcht ueber eine explizite EntityType-Tabelle, schreibt IMMER direkt auf die rohe LiteDB- Collection, nie ueber eine Repository-Save/Delete-Methode - sonst wuerde der OnChange-Hook (Baustein 2) die gerade angewendete Aenderung als neues ausgehendes Ereignis re-enqueuen (Sync-Ping-Pong). Ein gemeinsames Suppress-Flag wurde geprueft und verworfen: SyncEngine laeuft per Timer nebenlaeufig zum UI-Thread, ein Flag koennte einen echten Nutzer-Save waehrenddessen verschlucken. Der direkte Collection- Zugriff ist zustandslos und dadurch korrekt. Kaskaden-Faelle nutzen dieselben internen LiteDbContext-Hilfsmethoden wie die Repositories (Baustein 4). Neu SyncEventPublisher, der den OnChange-Hook in ein verschluesseltes EventQueue.Enqueue uebersetzt (an LiteDbContext.OnChange gehaengt). Mit dediziertem Loop-Prevention-Test abgesichert: belegt mit echtem LiteDbContext + OnChange-Zaehler, dass Apply keinen neuen Hook-Aufruf ausloest. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -178,9 +178,15 @@ public static class AppBootstrapper
|
||||
|
||||
if (!string.IsNullOrEmpty(serverUrl))
|
||||
{
|
||||
services.AddSingleton(sp => new EventApplier(
|
||||
sp.GetRequiredService<LiteDbContext>(), sp.GetRequiredService<byte[]>()));
|
||||
services.AddSingleton(sp => new SyncEventPublisher(
|
||||
sp.GetRequiredService<EventQueue>(), deviceId, sp.GetRequiredService<byte[]>()));
|
||||
|
||||
services.AddSingleton<SyncEngine>(sp => new SyncEngine(
|
||||
sp.GetRequiredService<EventQueue>(),
|
||||
sp.GetRequiredService<ConflictResolver>(),
|
||||
sp.GetRequiredService<EventApplier>(),
|
||||
BuildHttp(serverUrl, appData),
|
||||
new SyncConfig
|
||||
{
|
||||
@@ -223,7 +229,15 @@ public static class AppBootstrapper
|
||||
services.AddTransient<AddGroupDialogViewModel>();
|
||||
services.AddTransient<SettingsViewModel>();
|
||||
|
||||
return services.BuildServiceProvider();
|
||||
var provider = services.BuildServiceProvider();
|
||||
|
||||
// Sync-agnostischer Hook auf LiteDbContext (siehe LiteDbContext.OnChange) wird erst hier,
|
||||
// außerhalb der Repository-Registrierung, mit der tatsächlichen Sync-Logik verbunden.
|
||||
if (!string.IsNullOrEmpty(serverUrl))
|
||||
provider.GetRequiredService<LiteDbContext>().OnChange =
|
||||
provider.GetRequiredService<SyncEventPublisher>().Publish;
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
// ── Hilfsmethoden ─────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user