From ece3cdf75a3c6965fd8a4152a01ea25a96e50943 Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Mon, 27 Jul 2026 00:36:37 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20report=20ALL=20errors=20to=20Forgejo=20?= =?UTF-8?q?=E2=80=94=20backend=204xx/5xx,=20unhandled=20exceptions,=20work?= =?UTF-8?q?er=20job=20failures?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - main.py: RequestLoggingMiddleware reports 4xx/5xx responses and unhandled exceptions to Forgejo - worker.py: Plugin activation failures and outbox job failures reported to Forgejo - 401/403 are NOT reported (expected auth/permission behavior) - All other errors (422, 404, 500, network, worker) ARE reported --- app/core/worker.py | 23 ++++++++++++++++++++++- app/main.py | 23 +++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/app/core/worker.py b/app/core/worker.py index e862094..3822774 100644 --- a/app/core/worker.py +++ b/app/core/worker.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +import traceback from typing import Any from arq.connections import RedisSettings @@ -133,6 +134,16 @@ async def on_startup(ctx: dict[str, Any]) -> None: logger.info(f"Worker: activated plugin {name}") except Exception as exc: logger.error(f"Worker: failed to activate plugin {name}: {exc}") + # Report worker startup errors to Forgejo + try: + from app.plugins.builtins.forgejo_error_reporter.service import report_error_to_forgejo + await report_error_to_forgejo({ + "message": f"[Worker] Plugin activation failed: {name}: {exc}", + "stack": traceback.format_exc(), + "context": {"plugin": name, "source": "worker_startup"}, + }) + except Exception: + pass await db.commit() # Register webhook dispatcher on the event bus @@ -204,9 +215,19 @@ async def process_outbox_job(ctx: dict[str, Any]) -> None: count = await process_outbox_batch(db, batch_size=50) if count: logger.info("Outbox: published %d events", count) - except Exception: + except Exception as exc: logger.error("Outbox processing failed", exc_info=True) await db.rollback() + # Report to Forgejo + try: + from app.plugins.builtins.forgejo_error_reporter.service import report_error_to_forgejo + await report_error_to_forgejo({ + "message": f"[Worker] Outbox processing failed: {exc}", + "stack": traceback.format_exc(), + "context": {"source": "worker_outbox_job"}, + }) + except Exception: + pass # Register the outbox job so it appears in get_all_jobs() diff --git a/app/main.py b/app/main.py index f414fb8..2fcebd8 100644 --- a/app/main.py +++ b/app/main.py @@ -85,11 +85,34 @@ class RequestLoggingMiddleware(BaseHTTPMiddleware): traceback_str=tb_str, tenant_id=tenant_id, ) + # Report to Forgejo error reporter + try: + from app.plugins.builtins.forgejo_error_reporter.service import report_error_to_forgejo + await report_error_to_forgejo({ + "message": f"[Backend] {method} {path}: {exc}", + "stack": tb_str, + "url": str(request.url), + "context": {"method": method, "path": path, "source": "backend_middleware"}, + }) + except Exception: + pass # Never let error reporting break the request raise duration_ms = (time.perf_counter() - start_time) * 1000 status_code = response.status_code + # Report 4xx and 5xx errors to Forgejo (except 401/403 which are expected) + if status_code >= 400 and status_code not in (401, 403): + try: + from app.plugins.builtins.forgejo_error_reporter.service import report_error_to_forgejo + await report_error_to_forgejo({ + "message": f"[Backend] {method} {path} → {status_code}", + "url": str(request.url), + "context": {"method": method, "path": path, "status": status_code, "source": "backend_response"}, + }) + except Exception: + pass # Never let error reporting break the response + # Try to get tenant_id from response headers or request state # (set by auth middleware/dependency — best-effort, never log credentials) record_request(