Review fixes: - mark_all_read now filters status IN (sent, delivered), preventing pending notifications from being incorrectly marked as read - schedule_notification tool: force UTC on naive datetimes, reject past dates (send immediately instead) - WebSocket notification payload now includes all fields matching NotificationResponse (user_id, channel, status, scheduled_at, etc.) - Centralized _serialize_notification helper in notification_sender - notification_sender: per-notification error handling with rollback - health_review: moved import json to module top level Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
45 lines
1.5 KiB
Python
45 lines
1.5 KiB
Python
"""Periodic job: send pending scheduled notifications via WebSocket."""
|
|
import logging
|
|
|
|
from app.database import async_session_factory
|
|
from app.services.notification_service import get_pending_scheduled, mark_as_sent
|
|
from app.services.ws_manager import manager
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _serialize_notification(notif) -> dict:
|
|
return {
|
|
"id": str(notif.id),
|
|
"user_id": str(notif.user_id),
|
|
"title": notif.title,
|
|
"body": notif.body,
|
|
"type": notif.type,
|
|
"channel": notif.channel,
|
|
"status": "sent",
|
|
"scheduled_at": notif.scheduled_at.isoformat() if notif.scheduled_at else None,
|
|
"sent_at": notif.sent_at.isoformat() if notif.sent_at else None,
|
|
"read_at": None,
|
|
"metadata": notif.metadata_,
|
|
"created_at": notif.created_at.isoformat(),
|
|
}
|
|
|
|
|
|
async def send_pending_notifications():
|
|
async with async_session_factory() as db:
|
|
pending = await get_pending_scheduled(db)
|
|
for notif in pending:
|
|
try:
|
|
notif.status = "sent"
|
|
from datetime import datetime, timezone
|
|
notif.sent_at = datetime.now(timezone.utc)
|
|
await db.commit()
|
|
|
|
await manager.send_to_user(notif.user_id, {
|
|
"type": "new_notification",
|
|
"notification": _serialize_notification(notif),
|
|
})
|
|
except Exception:
|
|
logger.exception(f"Failed to send notification {notif.id}")
|
|
await db.rollback()
|