#!/usr/bin/env python3 """ Backfill script to send missed alert notifications Processes all active alerts and notifies users about matching listings they missed """ import asyncio import sys from pathlib import Path # Add parent directory to path sys.path.insert(0, str(Path(__file__).parent.parent)) from app.database import connect_db, disconnect_db, get_db from app.services.alert_service import process_new_listing from bson import ObjectId import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) async def backfill_alert_notifications(): """Process all active listings against all active alerts""" try: # Connect to database await connect_db() db = await get_db() # Get all active alerts alerts = await db.search_alerts.find({"is_active": True}).to_list(length=None) logger.info(f"Found {len(alerts)} active alerts") if not alerts: logger.info("No active alerts to process") return # Get all active listings listings = await db.listings.find({"status": "active"}).to_list(length=None) logger.info(f"Found {len(listings)} active listings") if not listings: logger.info("No active listings to process") return # Process each listing against all alerts notification_count = 0 for listing in listings: logger.info(f"Processing listing: {listing.get('title')} ({listing.get('_id')})") try: # Use the existing process_new_listing function which: # - Checks all active alerts # - Filters out owner's own alerts # - Only notifies if last_notified_at is old enough matches = await process_new_listing(listing) if matches > 0: notification_count += matches logger.info(f" ✅ Sent {matches} notification(s)") except Exception as e: logger.error(f" ❌ Error processing listing {listing.get('_id')}: {e}") continue logger.info(f"\n{'='*60}") logger.info(f"Backfill complete!") logger.info(f"Processed {len(listings)} listings") logger.info(f"Sent {notification_count} total notifications") logger.info(f"{'='*60}\n") except Exception as e: logger.error(f"Backfill failed: {e}") raise finally: await disconnect_db() if __name__ == "__main__": logger.info("Starting alert notification backfill...") asyncio.run(backfill_alert_notifications())