feat(app): ghi log khi app văng/treo và báo "Đang xử lý…" khi giao diện đứng

App văng ra với mã 0xC0000409 mà không để lại dấu vết: lỗi ở tầng native không in
traceback Python và console đóng theo app. crash_guard ghi vào
~/.cowork_local/logs/:

- crash.log: stack mọi luồng lúc tiến trình chết (faulthandler), cùng exception
  Python không ai bắt ở luồng chính lẫn luồng nền (chỉ ghi, app chạy tiếp).
- qt.log: cảnh báo/lỗi của Qt.
- hang.log: stack mọi luồng mỗi khi luồng giao diện đứng quá 5 giây.

Khi giao diện đứng, một luồng canh mở hộp thoại Windows "Đang xử lý…" (theo ngôn
ngữ đang chọn trong app) và tự đóng khi app phản hồi lại. Cài đặt bọc trong try,
không bao giờ chặn app khởi động.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
minhanhpkpro
2026-09-25 14:40:06 +09:00
co-authored by Claude Opus 5.5
parent 0b6b220bd9
commit a6b68a0bf8
4 changed files with 285 additions and 0 deletions
+12
View File
@@ -72,6 +72,12 @@ def run(argv: List[str] | None = None) -> int:
app = QApplication.instance() or QApplication(argv)
app.setApplicationName(APP_NAME)
app.setWindowIcon(app_icon())
try:
from .config import CONFIG_DIR
from .presentation.shell import crash_guard
crash_guard.install(Path(CONFIG_DIR) / "logs")
except Exception: # noqa: BLE001 - crash logging must never block startup
crash_guard = None
# Composition Root: presentation/shell/bootstrap.py quyết định app chạy
# bằng mảnh nào. Từ R02, đó là JsonConfigRepository + kho bí mật của hệ
# điều hành, không còn config.py::AppConfig.
@@ -132,4 +138,10 @@ def run(argv: List[str] | None = None) -> int:
pass
win.show()
if crash_guard is not None:
try:
watchdog = crash_guard.HangWatchdog(DISPLAY_NAME, win)
app.aboutToQuit.connect(watchdog.stop)
except Exception: # noqa: BLE001
pass
return app.exec()