deliveryman-api/app/core/scheduler.py
2025-03-11 08:09:04 +08:00

171 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor
from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.interval import IntervalTrigger
from apscheduler.triggers.date import DateTrigger
from datetime import datetime
import logging
import pytz
logger = logging.getLogger(__name__)
class TaskScheduler:
"""定时任务调度器"""
def __init__(self, timezone='Asia/Shanghai'):
"""初始化调度器"""
self.timezone = pytz.timezone(timezone)
# 配置作业存储和执行器
jobstores = {
'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
}
executors = {
'default': ThreadPoolExecutor(20), # 默认线程池
'processpool': ProcessPoolExecutor(5) # 进程池
}
job_defaults = {
'coalesce': False, # 是否合并执行
'max_instances': 3, # 最大实例数
'misfire_grace_time': 60 # 任务错过执行时间的宽限时间(秒)
}
# 创建调度器
self.scheduler = AsyncIOScheduler(
jobstores=jobstores,
executors=executors,
job_defaults=job_defaults,
timezone=self.timezone
)
def start(self):
"""启动调度器"""
if not self.scheduler.running:
self.scheduler.start()
logger.info("定时任务调度器已启动")
def shutdown(self):
"""关闭调度器"""
if self.scheduler.running:
self.scheduler.shutdown()
logger.info("定时任务调度器已关闭")
def add_cron_job(self, func, job_id=None, **trigger_args):
"""添加Cron定时任务
参数:
func: 要执行的函数
job_id: 任务ID如果不指定则自动生成
trigger_args: cron触发器参数如:
year (int|str) 4位数年份
month (int|str) 月份 (1-12)
day (int|str) 日期 (1-31)
week (int|str) ISO周数 (1-53)
day_of_week (int|str) 工作日 (0-6 或 mon,tue,wed,thu,fri,sat,sun)
hour (int|str) 小时 (0-23)
minute (int|str) 分钟 (0-59)
second (int|str) 秒 (0-59)
示例:
# 每天凌晨2点执行
scheduler.add_cron_job(my_function, hour=2)
# 每周一、三、五的下午5:30执行
scheduler.add_cron_job(my_function, day_of_week='mon,wed,fri', hour=17, minute=30)
"""
trigger = CronTrigger(**trigger_args, timezone=self.timezone)
return self.scheduler.add_job(
func,
trigger=trigger,
id=job_id,
replace_existing=True
)
def add_interval_job(self, func, seconds=0, minutes=0, hours=0, days=0, job_id=None):
"""添加间隔定时任务
参数:
func: 要执行的函数
seconds: 间隔秒数
minutes: 间隔分钟数
hours: 间隔小时数
days: 间隔天数
job_id: 任务ID如果不指定则自动生成
示例:
# 每30分钟执行一次
scheduler.add_interval_job(my_function, minutes=30)
"""
trigger = IntervalTrigger(
seconds=seconds,
minutes=minutes,
hours=hours,
days=days,
timezone=self.timezone
)
return self.scheduler.add_job(
func,
trigger=trigger,
id=job_id,
replace_existing=True
)
def add_one_time_job(self, func, run_date, job_id=None):
"""添加一次性定时任务
参数:
func: 要执行的函数
run_date: 运行日期时间
job_id: 任务ID如果不指定则自动生成
示例:
# 在指定时间执行一次
scheduler.add_one_time_job(my_function, datetime(2023, 12, 31, 23, 59, 59))
"""
trigger = DateTrigger(run_date=run_date, timezone=self.timezone)
return self.scheduler.add_job(
func,
trigger=trigger,
id=job_id,
replace_existing=True
)
def remove_job(self, job_id):
"""移除定时任务"""
try:
self.scheduler.remove_job(job_id)
logger.info(f"已移除任务: {job_id}")
return True
except Exception as e:
logger.error(f"移除任务失败: {job_id}, 错误: {str(e)}")
return False
def get_jobs(self):
"""获取所有定时任务"""
return self.scheduler.get_jobs()
def pause_job(self, job_id):
"""暂停定时任务"""
try:
self.scheduler.pause_job(job_id)
logger.info(f"已暂停任务: {job_id}")
return True
except Exception as e:
logger.error(f"暂停任务失败: {job_id}, 错误: {str(e)}")
return False
def resume_job(self, job_id):
"""恢复定时任务"""
try:
self.scheduler.resume_job(job_id)
logger.info(f"已恢复任务: {job_id}")
return True
except Exception as e:
logger.error(f"恢复任务失败: {job_id}, 错误: {str(e)}")
return False
# 创建全局调度器实例
scheduler = TaskScheduler()