import logging from apscheduler.triggers.interval import IntervalTrigger from django.utils.timezone import now from core.scheduler import scheduler logger = logging.getLogger(__name__) def check_watcher(watcher_pk: int) -> None: from pricemon.models import PriceWatcher, PriceSnapshot, PriceAlert from pricemon.scraper import fetch_price from pricemon.notifications import notify_telegram try: watcher = PriceWatcher.objects.get(pk=watcher_pk) except PriceWatcher.DoesNotExist: logger.warning(f'PriceWatcher {watcher_pk} no longer exists, skipping') return price, raw_text, error = fetch_price(watcher) PriceSnapshot.objects.create( watcher=watcher, price=price, raw_text=raw_text or '', error=error or '', ) if price is not None and watcher.alert_price_threshold: if price <= watcher.alert_price_threshold: should_alert = True if not watcher.recurring_notification: # Only alert if there is no undismissed alert already if PriceAlert.objects.filter(watcher=watcher, dismissed=False).exists(): should_alert = False if should_alert: old_price = watcher.last_price drop_pct = 0 if old_price and old_price > price: drop_pct = (old_price - price) / old_price * 100 alert = PriceAlert.objects.create( watcher=watcher, old_price=old_price, new_price=price, drop_pct=drop_pct, ) notify_telegram(watcher, alert) update_fields = ['last_checked_at'] if price is not None: if watcher.initial_price is None: watcher.initial_price = price update_fields.append('initial_price') watcher.last_price = price update_fields.append('last_price') watcher.last_checked_at = now() watcher.save(update_fields=update_fields) logger.info(f'Checked watcher {watcher_pk} ({watcher.name}): price={price}') def schedule_watcher(watcher) -> None: job_id = f'pricemon_watcher_{watcher.pk}' scheduler.add_job( check_watcher, trigger=IntervalTrigger(hours=watcher.check_interval_hours), id=job_id, args=[watcher.pk], replace_existing=True, ) logger.info(f'Scheduled pricemon job {job_id} every {watcher.check_interval_hours}h') def unschedule_watcher(watcher) -> None: job_id = f'pricemon_watcher_{watcher.pk}' if scheduler.get_job(job_id): scheduler.remove_job(job_id) logger.info(f'Removed pricemon job {job_id}')