Add Reddit monitoring bot — backend, frontend, and Docker config
Python/FastAPI backend with PostgreSQL for collecting Reddit data via public .json endpoints. React/Vite dashboard for analytics. Docker Compose setup with API and worker services connecting to shared PostgreSQL. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
90
backend/worker/main.py
Normal file
90
backend/worker/main.py
Normal file
@@ -0,0 +1,90 @@
|
||||
import logging
|
||||
import signal
|
||||
import sys
|
||||
|
||||
from apscheduler.schedulers.blocking import BlockingScheduler
|
||||
from apscheduler.triggers.interval import IntervalTrigger
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
|
||||
from backend.config import settings
|
||||
from backend.worker.monitor import poll_new_posts, poll_hot_posts, collect_comments, update_scores
|
||||
from backend.worker.snapshot import take_metric_snapshots
|
||||
from backend.worker.digest_job import generate_daily_digests
|
||||
from backend.worker.summary_job import generate_summaries
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def seed_subreddits():
|
||||
"""Add seed subreddits on first startup if configured."""
|
||||
if not settings.seed_subreddits:
|
||||
return
|
||||
from sqlalchemy import select, create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from backend.models.subreddit import MonitoredSubreddit
|
||||
|
||||
engine = create_engine(settings.database_url_sync)
|
||||
Session = sessionmaker(engine)
|
||||
|
||||
names = [s.strip().lower() for s in settings.seed_subreddits.split(",") if s.strip()]
|
||||
with Session() as db:
|
||||
for name in names:
|
||||
existing = db.execute(
|
||||
select(MonitoredSubreddit).where(MonitoredSubreddit.name == name)
|
||||
).scalar_one_or_none()
|
||||
if not existing:
|
||||
db.add(MonitoredSubreddit(name=name))
|
||||
logger.info(f"Seeded subreddit: r/{name}")
|
||||
db.commit()
|
||||
engine.dispose()
|
||||
|
||||
|
||||
def main():
|
||||
logger.info("Starting Reddit monitor worker")
|
||||
seed_subreddits()
|
||||
|
||||
scheduler = BlockingScheduler()
|
||||
|
||||
# Reddit polling jobs
|
||||
scheduler.add_job(poll_new_posts, IntervalTrigger(minutes=2), id="poll_new", max_instances=1)
|
||||
scheduler.add_job(poll_hot_posts, IntervalTrigger(minutes=2), id="poll_hot", max_instances=1)
|
||||
scheduler.add_job(collect_comments, IntervalTrigger(minutes=5), id="comments", max_instances=1)
|
||||
scheduler.add_job(update_scores, IntervalTrigger(minutes=15), id="scores", max_instances=1)
|
||||
|
||||
# Metric snapshots
|
||||
scheduler.add_job(take_metric_snapshots, IntervalTrigger(minutes=30), id="snapshots", max_instances=1)
|
||||
|
||||
# Daily digest
|
||||
scheduler.add_job(
|
||||
generate_daily_digests,
|
||||
CronTrigger(hour=settings.digest_hour_utc, minute=0),
|
||||
id="digest",
|
||||
max_instances=1,
|
||||
)
|
||||
|
||||
# AI summary stub
|
||||
scheduler.add_job(
|
||||
generate_summaries,
|
||||
CronTrigger(hour=settings.digest_hour_utc, minute=30),
|
||||
id="summary",
|
||||
max_instances=1,
|
||||
)
|
||||
|
||||
def shutdown(signum, frame):
|
||||
logger.info("Shutting down worker...")
|
||||
scheduler.shutdown(wait=False)
|
||||
sys.exit(0)
|
||||
|
||||
signal.signal(signal.SIGTERM, shutdown)
|
||||
signal.signal(signal.SIGINT, shutdown)
|
||||
|
||||
logger.info("Worker started. Scheduled jobs are running.")
|
||||
scheduler.start()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user