feat: add operations health and domain setup polish
This commit is contained in:
@@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
import hashlib
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -33,7 +33,7 @@ class CloudflareCredentials:
|
||||
|
||||
|
||||
def _utcnow_naive() -> datetime:
|
||||
return datetime.now(UTC).replace(tzinfo=None)
|
||||
return datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
|
||||
|
||||
def _plain_setting_value(db: Session, key: str) -> Optional[str]:
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
import hashlib
|
||||
import json
|
||||
from dataclasses import asdict
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import List, Tuple
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -17,7 +17,7 @@ DEFAULT_DNS_CACHE_TTL_SECONDS = 900
|
||||
|
||||
|
||||
def _utcnow_naive() -> datetime:
|
||||
return datetime.now(UTC).replace(tzinfo=None)
|
||||
return datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
|
||||
|
||||
def _selectors_key(selectors: List[str]) -> str:
|
||||
|
||||
@@ -392,7 +392,7 @@ class IMAPClient:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _append_detail(stats: dict | None, **detail: str) -> None:
|
||||
def _append_detail(stats: Optional[Dict[str, Any]], **detail: str) -> None:
|
||||
"""Append a compact attachment/message outcome to the import stats."""
|
||||
if stats is None:
|
||||
return
|
||||
@@ -405,8 +405,8 @@ class IMAPClient:
|
||||
report: Dict[str, Any],
|
||||
*,
|
||||
filename: str,
|
||||
stats: dict | None,
|
||||
message_id: str | None,
|
||||
stats: Optional[Dict[str, Any]],
|
||||
message_id: Optional[str],
|
||||
) -> bool:
|
||||
domain = report.get("domain", "unknown")
|
||||
report_id = report.get("report_id", "")
|
||||
@@ -445,8 +445,8 @@ class IMAPClient:
|
||||
part: email.message.Message,
|
||||
*,
|
||||
filename: str,
|
||||
stats: dict | None,
|
||||
message_id: str | None,
|
||||
stats: Optional[Dict[str, Any]],
|
||||
message_id: Optional[str],
|
||||
) -> bool:
|
||||
try:
|
||||
content = part.get_payload(decode=True)
|
||||
@@ -487,8 +487,8 @@ class IMAPClient:
|
||||
def _process_attachments(
|
||||
self,
|
||||
msg: email.message.Message,
|
||||
stats: dict | None = None,
|
||||
message_id: str | None = None,
|
||||
stats: Optional[Dict[str, Any]] = None,
|
||||
message_id: Optional[str] = None,
|
||||
) -> int:
|
||||
"""
|
||||
Process email attachments that might be DMARC reports
|
||||
|
||||
@@ -191,7 +191,7 @@ def persisted_report_to_dict(report: DMARCReport) -> Dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def hydrate_report_store_from_db(db: Session, store: ReportStore | None = None) -> int:
|
||||
def hydrate_report_store_from_db(db: Session, store: Optional[ReportStore] = None) -> int:
|
||||
"""Load persisted reports into ReportStore when the database has report rows."""
|
||||
report_count = db.query(DMARCReport.id).count()
|
||||
if report_count == 0:
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
"""Small in-process status tracker for scheduler health."""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
|
||||
_scheduler_state: Dict[str, Any] = {
|
||||
"running": False,
|
||||
"started_at": None,
|
||||
"stopped_at": None,
|
||||
"last_cycle_started_at": None,
|
||||
"last_success_at": None,
|
||||
"last_error_at": None,
|
||||
"last_error": None,
|
||||
}
|
||||
|
||||
|
||||
def _iso(value: Optional[datetime]) -> Optional[str]:
|
||||
return value.isoformat() if value else None
|
||||
|
||||
|
||||
def mark_scheduler_started() -> None:
|
||||
now = datetime.utcnow()
|
||||
_scheduler_state.update(
|
||||
{
|
||||
"running": True,
|
||||
"started_at": now,
|
||||
"stopped_at": None,
|
||||
"last_error": None,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def mark_scheduler_stopped() -> None:
|
||||
_scheduler_state.update({"running": False, "stopped_at": datetime.utcnow()})
|
||||
|
||||
|
||||
def mark_scheduler_cycle_started() -> None:
|
||||
_scheduler_state["last_cycle_started_at"] = datetime.utcnow()
|
||||
|
||||
|
||||
def mark_scheduler_success() -> None:
|
||||
_scheduler_state.update({"last_success_at": datetime.utcnow(), "last_error": None})
|
||||
|
||||
|
||||
def mark_scheduler_error(error: object) -> None:
|
||||
text = str(error)
|
||||
_scheduler_state.update(
|
||||
{
|
||||
"last_error_at": datetime.utcnow(),
|
||||
"last_error": text[:300],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def get_scheduler_status() -> Dict[str, Any]:
|
||||
return {
|
||||
"running": bool(_scheduler_state["running"]),
|
||||
"started_at": _iso(_scheduler_state["started_at"]),
|
||||
"stopped_at": _iso(_scheduler_state["stopped_at"]),
|
||||
"last_cycle_started_at": _iso(_scheduler_state["last_cycle_started_at"]),
|
||||
"last_success_at": _iso(_scheduler_state["last_success_at"]),
|
||||
"last_error_at": _iso(_scheduler_state["last_error_at"]),
|
||||
"last_error": _scheduler_state["last_error"],
|
||||
}
|
||||
Reference in New Issue
Block a user