fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled
Some checks failed
Deploy Application / deploy (push) Has been cancelled
This commit is contained in:
317
docs/refactoring/discovery-registry-loading-analysis.md
Normal file
317
docs/refactoring/discovery-registry-loading-analysis.md
Normal file
@@ -0,0 +1,317 @@
|
||||
# Discovery Registry Loading - Problem-Analyse und Refactoring-Vorschläge
|
||||
|
||||
## Problem-Identifikation
|
||||
|
||||
### Aktuelles Problem
|
||||
Die `DiscoveryRegistry` wird über **zwei verschiedene Mechanismen** geladen, was zu Inkonsistenzen führt:
|
||||
|
||||
1. **`DiscoveryServiceBootstrapper::bootstrap()`** (Runtime)
|
||||
- Wird in `ContainerBootstrapper::autowire()` aufgerufen
|
||||
- Verwendet `DiscoveryCacheManager` mit `isStale()` Prüfung
|
||||
- Registriert `DiscoveryRegistry` als Singleton im Container
|
||||
- Führt Discovery durch, wenn Cache stale ist oder nicht existiert
|
||||
|
||||
2. **`DiscoveryRegistryInitializer`** (Build-Time)
|
||||
- Ist ein `#[Initializer(ContextType::ALL)]`
|
||||
- Lädt aus `storage/discovery/` Dateien (Build-Time Storage)
|
||||
- Wird möglicherweise vor/nach `DiscoveryServiceBootstrapper` ausgeführt
|
||||
- Kann eine alte Registry laden, die dann als Singleton registriert wird
|
||||
|
||||
### Konflikt-Szenario
|
||||
|
||||
**Szenario 1: DiscoveryRegistryInitializer läuft zuerst**
|
||||
```
|
||||
1. DiscoveryRegistryInitializer läuft (Initializer-System)
|
||||
2. Lädt alte Registry aus storage/discovery/ (ohne DatabaseAssetGalleryDataProvider)
|
||||
3. Registriert als Singleton im Container
|
||||
4. DiscoveryServiceBootstrapper läuft
|
||||
5. Prüft Cache -> findet alte Registry (nicht stale, weil Datei vor Cache-Erstellung geändert wurde)
|
||||
6. Verwendet alte Registry -> Provider fehlt
|
||||
```
|
||||
|
||||
**Szenario 2: DiscoveryServiceBootstrapper läuft zuerst**
|
||||
```
|
||||
1. DiscoveryServiceBootstrapper läuft (autowire)
|
||||
2. Führt Discovery durch -> findet DatabaseAssetGalleryDataProvider
|
||||
3. Registriert als Singleton
|
||||
4. DiscoveryRegistryInitializer läuft später
|
||||
5. Lädt alte Registry aus storage/discovery/
|
||||
6. Überschreibt Singleton? -> Provider geht verloren
|
||||
```
|
||||
|
||||
## Root Cause Analysis
|
||||
|
||||
### Problem 1: Zwei verschiedene Cache-Mechanismen
|
||||
- **Runtime-Cache**: `DiscoveryCacheManager` mit `isStale()` Prüfung
|
||||
- **Build-Time Storage**: `storage/discovery/` Dateien (veraltet?)
|
||||
|
||||
### Problem 2: Unklare Ausführungsreihenfolge
|
||||
- `DiscoveryServiceBootstrapper` läuft in `autowire()` (explizit)
|
||||
- `DiscoveryRegistryInitializer` läuft über Initializer-System (automatisch)
|
||||
- Keine garantierte Reihenfolge
|
||||
|
||||
### Problem 3: isStale() Prüfung funktioniert nicht korrekt
|
||||
- **BEHOBEN**: Verwendet jetzt Cache-Erstellungszeit statt Request-Zeit
|
||||
- Aber: Wenn `DiscoveryRegistryInitializer` eine alte Registry lädt, wird diese nicht als stale erkannt
|
||||
|
||||
## Refactoring-Vorschläge
|
||||
|
||||
### Option 1: DiscoveryRegistryInitializer entfernen (Empfohlen)
|
||||
|
||||
**Vorteile:**
|
||||
- Eliminiert Konflikt zwischen zwei Mechanismen
|
||||
- Einheitliche Cache-Strategie über `DiscoveryCacheManager`
|
||||
- `isStale()` Prüfung funktioniert korrekt
|
||||
|
||||
**Nachteile:**
|
||||
- Build-Time Storage wird nicht mehr verwendet
|
||||
- Möglicherweise Performance-Verlust beim ersten Request
|
||||
|
||||
**Implementierung:**
|
||||
1. `DiscoveryRegistryInitializer` entfernen oder deaktivieren
|
||||
2. Sicherstellen, dass `DiscoveryServiceBootstrapper` immer läuft
|
||||
3. `DiscoveryCacheManager` als einzige Quelle für Discovery-Registry
|
||||
|
||||
### Option 2: DiscoveryRegistryInitializer als Fallback
|
||||
|
||||
**Vorteile:**
|
||||
- Behält Build-Time Storage für Performance
|
||||
- Fallback wenn Runtime-Cache nicht verfügbar
|
||||
|
||||
**Nachteile:**
|
||||
- Komplexere Logik
|
||||
- Mögliche Inkonsistenzen zwischen Build-Time und Runtime
|
||||
|
||||
**Implementierung:**
|
||||
1. `DiscoveryServiceBootstrapper` prüft zuerst Runtime-Cache
|
||||
2. Wenn nicht verfügbar/stale, prüft `DiscoveryRegistryInitializer`
|
||||
3. Nur wenn beide fehlschlagen, führt Discovery durch
|
||||
|
||||
### Option 3: Einheitliche Cache-Strategie
|
||||
|
||||
**Vorteile:**
|
||||
- Einheitliche Quelle für Discovery-Registry
|
||||
- Klare Verantwortlichkeiten
|
||||
|
||||
**Nachteile:**
|
||||
- Größere Refactoring-Arbeit
|
||||
|
||||
**Implementierung:**
|
||||
1. `DiscoveryCacheManager` verwendet `storage/discovery/` als Backend
|
||||
2. `DiscoveryRegistryInitializer` entfernen
|
||||
3. `DiscoveryServiceBootstrapper` verwendet nur `DiscoveryCacheManager`
|
||||
|
||||
### Option 4: Priority-basierte Ausführungsreihenfolge
|
||||
|
||||
**Vorteile:**
|
||||
- Beide Mechanismen bleiben erhalten
|
||||
- Klare Ausführungsreihenfolge
|
||||
|
||||
**Nachteile:**
|
||||
- Komplexere Initializer-Logik
|
||||
- Mögliche Race-Conditions
|
||||
|
||||
**Implementierung:**
|
||||
1. `DiscoveryServiceBootstrapper` mit höherer Priority
|
||||
2. `DiscoveryRegistryInitializer` prüft ob Registry bereits existiert
|
||||
3. Nur laden wenn nicht vorhanden
|
||||
|
||||
## Empfohlene Lösung: Option 1 + Verbesserungen
|
||||
|
||||
### Schritt 1: DiscoveryRegistryInitializer deaktivieren/entfernen
|
||||
|
||||
```php
|
||||
// DiscoveryRegistryInitializer.php
|
||||
#[Initializer(ContextType::ALL)]
|
||||
public function __invoke(): DiscoveryRegistry
|
||||
{
|
||||
// DEPRECATED: This initializer is deprecated in favor of DiscoveryServiceBootstrapper
|
||||
// Check if DiscoveryRegistry already exists (from DiscoveryServiceBootstrapper)
|
||||
if ($this->container->has(DiscoveryRegistry::class)) {
|
||||
return $this->container->get(DiscoveryRegistry::class);
|
||||
}
|
||||
|
||||
// Fallback: Load from storage (for backward compatibility)
|
||||
$attributes = $this->discoveryLoader->loadAttributes() ?? new AttributeRegistry();
|
||||
$interfaces = $this->discoveryLoader->loadInterfaces() ?? new InterfaceRegistry();
|
||||
$templates = $this->discoveryLoader->loadTemplates() ?? new TemplateRegistry();
|
||||
|
||||
return new DiscoveryRegistry(
|
||||
attributes: $attributes,
|
||||
interfaces: $interfaces,
|
||||
templates: $templates
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Schritt 2: DiscoveryServiceBootstrapper als einzige Quelle
|
||||
|
||||
```php
|
||||
// DiscoveryServiceBootstrapper.php
|
||||
public function bootstrap(): DiscoveryRegistry
|
||||
{
|
||||
// Prüfe ob bereits registriert (z.B. durch DiscoveryRegistryInitializer)
|
||||
if ($this->container->has(DiscoveryRegistry::class)) {
|
||||
$existing = $this->container->get(DiscoveryRegistry::class);
|
||||
|
||||
// Prüfe ob stale
|
||||
if ($this->isRegistryStale($existing)) {
|
||||
// Force refresh
|
||||
$this->container->forget(DiscoveryRegistry::class);
|
||||
} else {
|
||||
return $existing;
|
||||
}
|
||||
}
|
||||
|
||||
// ... rest of bootstrap logic
|
||||
}
|
||||
```
|
||||
|
||||
### Schritt 3: Verbesserte isStale() Prüfung
|
||||
|
||||
```php
|
||||
// DiscoveryCacheManager.php
|
||||
private function isStale(DiscoveryContext $context, DiscoveryRegistry $registry, ?\DateTimeInterface $cacheStartTime = null): bool
|
||||
{
|
||||
// ... existing logic
|
||||
|
||||
// ZUSÄTZLICH: Prüfe ob Dateien seit Cache-Erstellung geändert wurden
|
||||
// Dies ist bereits implementiert, aber sollte auch für Build-Time Storage gelten
|
||||
}
|
||||
```
|
||||
|
||||
## Weitere Verbesserungen
|
||||
|
||||
### 1. Discovery-Registry Versionierung
|
||||
- Jede Registry hat eine Version/Timestamp
|
||||
- Vergleich zwischen Build-Time und Runtime-Cache
|
||||
- Automatische Invalidation bei Versionsunterschieden
|
||||
|
||||
### 2. Unified Discovery Storage
|
||||
- Einheitliche Storage-Strategie für Build-Time und Runtime
|
||||
- `DiscoveryCacheManager` verwendet `storage/discovery/` als Backend
|
||||
- Konsistente Cache-Invalidation
|
||||
|
||||
### 3. Discovery-Registry Factory
|
||||
- Zentrale Factory für Discovery-Registry-Erstellung
|
||||
- Einheitliche Logik für alle Quellen
|
||||
- Klare Verantwortlichkeiten
|
||||
|
||||
### 4. Logging und Monitoring
|
||||
- Besseres Logging für Discovery-Registry-Loading
|
||||
- Metriken für Cache-Hits/Misses
|
||||
- Warnungen bei Inkonsistenzen
|
||||
|
||||
## Migration-Plan
|
||||
|
||||
1. **Phase 1**: `DiscoveryRegistryInitializer` als Fallback behalten, aber prüfen ob Registry bereits existiert
|
||||
2. **Phase 2**: `DiscoveryServiceBootstrapper` prüft ob Registry stale ist, auch wenn bereits registriert
|
||||
3. **Phase 3**: `DiscoveryRegistryInitializer` vollständig entfernen
|
||||
4. **Phase 4**: Build-Time Storage optional machen (nur für Performance-Optimierung)
|
||||
|
||||
## Testing-Strategie
|
||||
|
||||
1. Unit-Tests für `DiscoveryCacheManager::isStale()`
|
||||
2. Integration-Tests für Discovery-Registry-Loading
|
||||
3. E2E-Tests für Provider-Resolution
|
||||
4. Performance-Tests für Cache-Hit-Rate
|
||||
|
||||
## Implementierte Änderungen
|
||||
|
||||
### 1. isStale() Prüfung korrigiert ✅
|
||||
- **Datei**: `src/Framework/Discovery/Storage/DiscoveryCacheManager.php`
|
||||
- **Änderung**: `isStale()` verwendet jetzt Cache-Erstellungszeit statt Request-Zeit
|
||||
- **Implementierung**: `startTime` wird beim Speichern im Cache gespeichert und beim Laden verwendet
|
||||
|
||||
### 2. DiscoveryRegistryInitializer entfernt ✅
|
||||
- **Datei**: `src/Framework/Discovery/DiscoveryRegistryInitializer.php` (entfernt)
|
||||
- **Änderung**: Initializer wurde vollständig entfernt, da er nur noch als No-Op fungierte
|
||||
- **Implementierung**: `DiscoveryServiceBootstrapper` ist jetzt die einzige Quelle für Discovery-Registry
|
||||
|
||||
### 3. DiscoveryServiceBootstrapper verbessert ✅
|
||||
- **Datei**: `src/Framework/Discovery/DiscoveryServiceBootstrapper.php`
|
||||
- **Änderung**: Prüft ob existierende Registry stale ist, bevor Discovery durchgeführt wird
|
||||
- **Implementierung**: `isRegistryStale()` Methode hinzugefügt
|
||||
|
||||
### 4. Cache-Struktur Migration ✅
|
||||
- **Datei**: `src/Framework/Discovery/Storage/DiscoveryCacheManager.php`
|
||||
- **Änderung**: Automatische Migration von altem Cache-Format zu neuem Format mit `startTime` und `version`
|
||||
- **Implementierung**: `upgradeCacheEntry()` und `validateCacheStructure()` Methoden hinzugefügt
|
||||
|
||||
### 5. Registry Versionierung ✅
|
||||
- **Datei**: `src/Framework/Discovery/Storage/DiscoveryCacheManager.php`
|
||||
- **Änderung**: Cache-Struktur erweitert um `version` Feld für Registry-Versionierung
|
||||
- **Implementierung**: `getRegistryVersion()` Methode erstellt Version basierend auf Registry-Content-Hash
|
||||
|
||||
### 6. Unified Discovery Storage ✅
|
||||
- **Datei**: `src/Framework/Discovery/Storage/DiscoveryCacheManager.php`
|
||||
- **Änderung**: Build-Time Storage als optionales Backend hinzugefügt
|
||||
- **Implementierung**: `tryGetFromBuildTimeStorage()` Methode prüft Build-Time Storage vor Runtime-Cache
|
||||
|
||||
### 7. Verbessertes Logging und Monitoring ✅
|
||||
- **Dateien**:
|
||||
- `src/Framework/Discovery/Storage/DiscoveryCacheManager.php`
|
||||
- `src/Framework/Discovery/Results/DiscoveryRegistry.php`
|
||||
- **Änderung**: Strukturiertes Logging, Metriken-Sammlung, Debug-Helpers hinzugefügt
|
||||
- **Implementierung**:
|
||||
- `getMetadata()` Methode in `DiscoveryRegistry`
|
||||
- `getSource()` Methode in `DiscoveryRegistry`
|
||||
- Erweiterte Logging-Statements mit Source-Informationen
|
||||
|
||||
## Weitere Refactoring-Vorschläge
|
||||
|
||||
### Refactoring 1: Einheitliche Cache-Struktur
|
||||
**Problem**: Cache-Struktur wurde geändert (Array mit `registry` und `startTime`), aber alte Caches haben noch das alte Format.
|
||||
|
||||
**Lösung**:
|
||||
- Migration-Script für alte Cache-Einträge
|
||||
- Oder: Automatische Erkennung und Konvertierung beim Laden
|
||||
|
||||
### Refactoring 2: DiscoveryRegistryInitializer entfernen
|
||||
**Problem**: Zwei Mechanismen für Discovery-Registry-Loading führen zu Konflikten.
|
||||
|
||||
**Lösung**:
|
||||
- `DiscoveryRegistryInitializer` vollständig entfernen
|
||||
- Oder: Nur als Fallback verwenden (bereits implementiert)
|
||||
- `DiscoveryServiceBootstrapper` als einzige Quelle
|
||||
|
||||
### Refactoring 3: Build-Time Storage optional machen
|
||||
**Problem**: Build-Time Storage (`storage/discovery/`) wird möglicherweise nicht mehr verwendet.
|
||||
|
||||
**Lösung**:
|
||||
- Build-Time Storage als Performance-Optimierung optional machen
|
||||
- Nur verwenden wenn verfügbar und aktuell
|
||||
- Runtime-Cache als primäre Quelle
|
||||
|
||||
### Refactoring 4: Discovery-Registry Versionierung
|
||||
**Problem**: Keine Möglichkeit, verschiedene Versionen der Registry zu vergleichen.
|
||||
|
||||
**Lösung**:
|
||||
- Jede Registry hat eine Version/Timestamp
|
||||
- Vergleich zwischen Build-Time und Runtime-Cache
|
||||
- Automatische Invalidation bei Versionsunterschieden
|
||||
|
||||
### Refactoring 5: Unified Discovery Storage
|
||||
**Problem**: Zwei verschiedene Storage-Mechanismen (Build-Time und Runtime).
|
||||
|
||||
**Lösung**:
|
||||
- Einheitliche Storage-Strategie
|
||||
- `DiscoveryCacheManager` verwendet `storage/discovery/` als Backend
|
||||
- Konsistente Cache-Invalidation
|
||||
|
||||
### Refactoring 6: Discovery-Registry Factory
|
||||
**Problem**: Discovery-Registry wird an mehreren Stellen erstellt.
|
||||
|
||||
**Lösung**:
|
||||
- Zentrale Factory für Discovery-Registry-Erstellung
|
||||
- Einheitliche Logik für alle Quellen
|
||||
- Klare Verantwortlichkeiten
|
||||
|
||||
### Refactoring 7: Verbessertes Logging
|
||||
**Problem**: Schwierig zu debuggen, welche Registry verwendet wird.
|
||||
|
||||
**Lösung**:
|
||||
- Besseres Logging für Discovery-Registry-Loading
|
||||
- Metriken für Cache-Hits/Misses
|
||||
- Warnungen bei Inkonsistenzen
|
||||
|
||||
Reference in New Issue
Block a user