1.0.0初始化源代码
This commit is contained in:
215
backend/app/services/scheduler_service.py
Normal file
215
backend/app/services/scheduler_service.py
Normal file
@@ -0,0 +1,215 @@
|
||||
"""
|
||||
定时任务调度服务
|
||||
基于 APScheduler 实现
|
||||
"""
|
||||
import logging
|
||||
import random
|
||||
import asyncio
|
||||
from typing import Optional, List
|
||||
from datetime import datetime, time
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from apscheduler.triggers.interval import IntervalTrigger
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models.virtual_user import VirtualUser, ActivityLevel, UserStatus
|
||||
from app.models.base import get_db, SessionLocal
|
||||
from app.services.interaction_service import InteractionService
|
||||
from app.core.config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SchedulerService:
|
||||
"""定时任务调度服务类"""
|
||||
|
||||
def __init__(self):
|
||||
self.scheduler = AsyncIOScheduler()
|
||||
self.is_running = False
|
||||
self._current_job = None
|
||||
|
||||
def start(self):
|
||||
"""启动调度器"""
|
||||
if not self.is_running:
|
||||
self.scheduler.start()
|
||||
self.is_running = True
|
||||
logger.info("Scheduler started")
|
||||
|
||||
def stop(self):
|
||||
"""停止调度器"""
|
||||
if self.is_running:
|
||||
self.scheduler.shutdown()
|
||||
self.is_running = False
|
||||
logger.info("Scheduler stopped")
|
||||
|
||||
def add_interaction_task(self):
|
||||
"""添加互动任务"""
|
||||
# 在活动时间段内,每隔随机时间执行一次互动
|
||||
# 由于 APScheduler 不支持随机间隔,我们使用固定间隔但通过概率控制执行
|
||||
|
||||
# 每 5 分钟检查一次
|
||||
trigger = IntervalTrigger(minutes=5)
|
||||
|
||||
self.scheduler.add_job(
|
||||
self._execute_random_interaction,
|
||||
trigger=trigger,
|
||||
id="random_interaction",
|
||||
name="Random Interaction Task",
|
||||
replace_existing=True
|
||||
)
|
||||
|
||||
logger.info("Interaction task added")
|
||||
|
||||
def remove_interaction_task(self):
|
||||
"""移除互动任务"""
|
||||
try:
|
||||
self.scheduler.remove_job("random_interaction")
|
||||
logger.info("Interaction task removed")
|
||||
except Exception as e:
|
||||
logger.warning(f"Remove interaction task error: {e}")
|
||||
|
||||
async def _execute_random_interaction(self):
|
||||
"""执行随机互动任务"""
|
||||
# 检查是否在活动时间段内
|
||||
now = datetime.now()
|
||||
current_hour = now.hour
|
||||
|
||||
if current_hour < settings.TASK_START_HOUR or current_hour > settings.TASK_END_HOUR:
|
||||
logger.debug(f"Outside activity hours: {current_hour}")
|
||||
return
|
||||
|
||||
# 随机决定是否执行(通过随机间隔模拟)
|
||||
if random.random() > 0.5: # 50% 概率执行
|
||||
logger.debug("Skip this round")
|
||||
return
|
||||
|
||||
logger.info("Executing random interaction task")
|
||||
|
||||
# 获取数据库会话
|
||||
db = SessionLocal()
|
||||
try:
|
||||
# 获取所有活跃的虚拟用户
|
||||
users = db.query(VirtualUser).filter(
|
||||
VirtualUser.status == UserStatus.ACTIVE,
|
||||
VirtualUser.is_logged_in == True
|
||||
).all()
|
||||
|
||||
if not users:
|
||||
logger.debug("No active logged-in users")
|
||||
return
|
||||
|
||||
# 随机选择一个用户
|
||||
user = random.choice(users)
|
||||
|
||||
# 检查用户活跃度
|
||||
if not self._should_user_interact(user):
|
||||
logger.debug(f"User {user.id} should not interact now")
|
||||
return
|
||||
|
||||
# 执行互动
|
||||
interaction_service = InteractionService(db)
|
||||
await interaction_service.execute_interaction(virtual_user_id=user.id)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Execute random interaction error: {e}")
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
def _should_user_interact(self, user: VirtualUser) -> bool:
|
||||
"""根据活跃度判断用户是否应该互动"""
|
||||
# 根据活跃度决定互动概率
|
||||
if user.activity_level == ActivityLevel.HIGH:
|
||||
# 高活跃度:80% 概率
|
||||
return random.random() < 0.8
|
||||
elif user.activity_level == ActivityLevel.MEDIUM:
|
||||
# 中活跃度:50% 概率
|
||||
return random.random() < 0.5
|
||||
else:
|
||||
# 低活跃度:30% 概率
|
||||
return random.random() < 0.3
|
||||
|
||||
def add_login_task(self, hour: int = 8, minute: int = 0):
|
||||
"""添加每日登录任务"""
|
||||
trigger = CronTrigger(hour=hour, minute=minute)
|
||||
|
||||
self.scheduler.add_job(
|
||||
self._auto_login_users,
|
||||
trigger=trigger,
|
||||
id="daily_login",
|
||||
name="Daily Auto Login",
|
||||
replace_existing=True
|
||||
)
|
||||
|
||||
logger.info(f"Daily login task added at {hour:02d}:{minute:02d}")
|
||||
|
||||
async def _auto_login_users(self):
|
||||
"""自动登录所有活跃用户"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
from app.services.huihui_api_service import huihui_api_service
|
||||
|
||||
users = db.query(VirtualUser).filter(
|
||||
VirtualUser.status == UserStatus.ACTIVE
|
||||
).all()
|
||||
|
||||
for user in users:
|
||||
try:
|
||||
# 调用登录接口
|
||||
result = await huihui_api_service.login(user.username, user.password)
|
||||
|
||||
if result and result.get("token"):
|
||||
user.is_logged_in = True
|
||||
user.session_token = result["token"]
|
||||
# TODO: 设置 token 过期时间
|
||||
|
||||
logger.info(f"Auto login success: {user.username}")
|
||||
else:
|
||||
logger.warning(f"Auto login failed: {user.username}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Auto login error for {user.username}: {e}")
|
||||
|
||||
db.commit()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Auto login task error: {e}")
|
||||
db.rollback()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
def reset_daily_counters(self, hour: int = 0, minute: int = 1):
|
||||
"""添加每日计数器重置任务"""
|
||||
trigger = CronTrigger(hour=hour, minute=minute)
|
||||
|
||||
self.scheduler.add_job(
|
||||
self._reset_daily_counters,
|
||||
trigger=trigger,
|
||||
id="reset_daily_counters",
|
||||
name="Reset Daily Counters",
|
||||
replace_existing=True
|
||||
)
|
||||
|
||||
logger.info(f"Daily reset task added at {hour:02d}:{minute:02d}")
|
||||
|
||||
def _reset_daily_counters(self):
|
||||
"""重置每日计数器"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
# 重置所有用户的今日计数
|
||||
db.query(VirtualUser).update({
|
||||
VirtualUser.today_comments: 0,
|
||||
VirtualUser.today_replies: 0
|
||||
})
|
||||
|
||||
db.commit()
|
||||
logger.info("Daily counters reset")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Reset daily counters error: {e}")
|
||||
db.rollback()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
# 创建全局服务实例
|
||||
scheduler_service = SchedulerService()
|
||||
Reference in New Issue
Block a user