3.40exit-crash-fix als plan in assets
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
# Plan: QGIS 3.40 Exit-Crash absichern
|
||||
|
||||
Der wahrscheinlichste Auslöser ist fehlendes Signal-Cleanup beim Plugin-Unload: globale Projekt-Listener und PrintTab-Listener bleiben aktiv, während QgsProject beim QGIS-Exit bereits zerstört wird. Die empfohlene Lösung ist ein minimaler, versionsneutraler Cleanup-Pfad (disconnect + defensive Guards), ohne Fachlogik zu ändern.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Teardown-Funktion für globale Verfahrensgebiet-Listener ergänzen, inkl. idempotentem Disconnect und Rücksetzen des Installationsflags.
|
||||
- Datei: `sn_basis/functions/verfahrensgebiet_manager.py` (nach `setup_verfahrensgebiet_listener`, ca. Zeile 132)
|
||||
- Neue Funktion `teardown_verfahrensgebiet_listener()` disconnect alle 5 QgsProject-Signale (`layersAdded`, `layerRemoved`, `readProject`, `newProjectCreated`, `cleared`) und setzt `_listener_installed = False` zurück.
|
||||
- RuntimeError abfangen (Projekt wird gerade zerstört → normal).
|
||||
|
||||
2. Teardown in Unload-Pfad vor UI-Abbau aufrufen. (depends on step 1)
|
||||
- Datei: `sn_basis/main.py` (in `BasisPlugin.unload`, ca. Zeile 52)
|
||||
- Import und Aufruf von `teardown_verfahrensgebiet_listener()` als erste Zeile in `unload()`, bevor `self.ui.remove_all()` ausgeführt wird.
|
||||
|
||||
3. PrintTab um kleinen Projekt-Signal-Cleanup ergänzen, symmetrisch zu bestehendem Theme-Cleanup. (parallel mit step 1)
|
||||
- Datei: `sn_basis/ui/tabs/print_tab.py`
|
||||
- Neue Methode `cleanup()` nach `_disconnect_theme_collection_signals` (ca. Zeile 485).
|
||||
- Disconnectet QgsProject-Signale (`readProject`, `newProjectCreated`, `cleared`) von `self._on_project_changed` (analog zu bestehendem Theme-Disconnect-Muster).
|
||||
- Ruft danach `self._disconnect_theme_collection_signals()` auf.
|
||||
|
||||
4. BaseDockWidget.closeEvent so erweitern, dass Tab-Cleanup-Hooks vor Schließen aufgerufen werden. (depends on step 3)
|
||||
- Datei: `sn_basis/ui/base_dockwidget.py` (in `closeEvent`, ca. Zeile 97)
|
||||
- Vor dem bestehenden `self.action.setChecked(False)` Block: über alle Tabs iterieren, auf `cleanup`-Attribut prüfen, aufrufen; Exception abfangen.
|
||||
|
||||
5. Optional nur bei Restinstabilität: defensive Guards bei Projektzugriffen in kritischen Handlern ergänzen.
|
||||
- Datei: `sn_basis/functions/variable_wrapper.py` (in `get_variable`/`set_variable`, ca. Zeile 60 und 89)
|
||||
- Datei: `sn_basis/functions/verfahrensgebiet_manager.py` (in `_on_layer_removed`, ca. Zeile 114)
|
||||
- `QgsProject.instance()` auf None/RuntimeError prüfen und bei Zerstörung früh zurückkehren.
|
||||
|
||||
## Relevant files
|
||||
|
||||
- `sn_basis/functions/verfahrensgebiet_manager.py` — Listener-Setup/Teardown, Handler-Guards
|
||||
- `sn_basis/main.py` — Unload-Reihenfolge
|
||||
- `sn_basis/ui/tabs/print_tab.py` — Projekt-Signal-Cleanup
|
||||
- `sn_basis/ui/base_dockwidget.py` — zentraler Cleanup-Hook
|
||||
- `sn_basis/ui/dockmanager.py` — asynchrones deleteLater als Lifecycle-Kontext
|
||||
- `sn_basis/functions/variable_wrapper.py` — optional defensive Guards
|
||||
|
||||
## Decisions
|
||||
|
||||
- Include: minimaler Lifecycle-Fix über disconnect + Guards.
|
||||
- Exclude: Refactoring der gesamten Signal-Architektur, größere UI-Umbauten, versionsspezifische If-Branches.
|
||||
- Begründung: geringstes Risiko für Regressionen bei maximaler Wirkung gegen Shutdown-Crashs.
|
||||
- Keine Änderung an Business-Logik, keine Änderung an Variablennamen, keine QGIS-versionsspezifischen Sonderpfade — rein sichere Disconnect/Guard-Muster.
|
||||
|
||||
## Verification
|
||||
|
||||
1. Plugin laden, Dock öffnen/schließen, Projekt neu laden, Layer „Verfahrensgebiet" add/remove, dann QGIS 3.40.7 beenden → kein Access Violation.
|
||||
2. Dasselbe unter QGIS 4 → unverändertes Verhalten, keine Regression.
|
||||
3. Mehrfacher Plugin-Reload in einer Sitzung → keine doppelten Signal-Reaktionen, keine Exceptions beim Unload.
|
||||
4. Optionaler Stresstest: Unit-Test für idempotentes Teardown (mehrfaches unload ohne Exception).
|
||||
|
||||
## Further considerations
|
||||
|
||||
- Step 5 (defensive Guards in variable_wrapper) nur umsetzen, wenn nach Steps 1–4 noch reproduzierbare Exit-Crashs auftreten.
|
||||
- Ein kleiner Unit-Test für idempotentes Teardown (mehrfaches `unload()` ohne Exception) wäre empfehlenswert, falls die Testsuite erweitert wird.
|
||||
Reference in New Issue
Block a user