Files
links/pricemon/tasks.py
T
2026-05-23 10:15:09 +10:00

83 lines
2.7 KiB
Python

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}')