Python Flask實(shí)現(xiàn)定時(shí)任務(wù)的不同方法詳解
在 Flask 中實(shí)現(xiàn)定時(shí)任務(wù),最常用的方法是使用 APScheduler 庫(kù)(Advanced Python Scheduler)。下面我將提供一個(gè)完整的解決方案,包含代碼實(shí)現(xiàn)、解釋和生產(chǎn)環(huán)境注意事項(xiàng)。
完整實(shí)現(xiàn)方案
from flask import Flask
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from datetime import datetime
app = Flask(__name__)
app.config['SCHEDULER_JOBSTORES'] = {
'default': SQLAlchemyJobStore(url='sqlite:///jobs.db')
}
# 創(chuàng)建調(diào)度器實(shí)例
scheduler = BackgroundScheduler(
jobstores=app.config['SCHEDULER_JOBSTORES'],
daemon=True
)
# 定義定時(shí)任務(wù)函數(shù)
def daily_report():
"""每天上午9點(diǎn)執(zhí)行的日?qǐng)?bào)任務(wù)"""
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"[日?qǐng)?bào)] 執(zhí)行時(shí)間: {current_time}")
# 這里添加實(shí)際的日?qǐng)?bào)生成邏輯
def every_5_minutes():
"""每5分鐘執(zhí)行一次的任務(wù)"""
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"[5分鐘任務(wù)] 執(zhí)行時(shí)間: {current_time}")
# 這里添加實(shí)際的任務(wù)邏輯
def on_startup():
"""應(yīng)用啟動(dòng)時(shí)添加定時(shí)任務(wù)"""
# 添加每天9:00執(zhí)行的任務(wù)
scheduler.add_job(
id='daily_report_job',
func=daily_report,
trigger='cron',
hour=9,
minute=0,
replace_existing=True
)
# 添加每5分鐘執(zhí)行的任務(wù)
scheduler.add_job(
id='every_5_minutes_job',
func=every_5_minutes,
trigger='interval',
minutes=5,
replace_existing=True
)
# 添加一次性任務(wù)(應(yīng)用啟動(dòng)后10秒執(zhí)行)
scheduler.add_job(
id='startup_check',
func=lambda: print("應(yīng)用啟動(dòng)完成!"),
trigger='date',
run_date=datetime.now() + timedelta(seconds=10)
)
# 啟動(dòng)調(diào)度器
if not scheduler.running:
scheduler.start()
on_startup()
@app.route('/')
def home():
return """
<h1>Flask 定時(shí)任務(wù)示例</h1>
<p>已啟動(dòng)的定時(shí)任務(wù):</p>
<ul>
<li>日?qǐng)?bào)任務(wù):每天9:00執(zhí)行</li>
<li>5分鐘任務(wù):每5分鐘執(zhí)行一次</li>
</ul>
<p>查看控制臺(tái)輸出獲取執(zhí)行詳情</p>
"""
@app.route('/jobs')
def list_jobs():
"""查看當(dāng)前所有定時(shí)任務(wù)"""
jobs = scheduler.get_jobs()
job_list = [f"ID: {job.id}, 下次執(zhí)行: {job.next_run_time}" for job in jobs]
return "
".join(job_list)
@app.route('/add_job/<minutes>')
def add_job(minutes):
"""動(dòng)態(tài)添加定時(shí)任務(wù)"""
try:
minutes = int(minutes)
job_id = f"dynamic_job_{minutes}min"
scheduler.add_job(
id=job_id,
func=lambda: print(f"動(dòng)態(tài)添加的任務(wù) - 每 {minutes} 分鐘執(zhí)行一次"),
trigger='interval',
minutes=minutes,
replace_existing=True
)
return f"成功添加每 {minutes} 分鐘執(zhí)行的任務(wù)!"
except ValueError:
return "參數(shù)錯(cuò)誤,請(qǐng)輸入有效的分鐘數(shù)"
@app.route('/remove_job/<job_id>')
def remove_job(job_id):
"""移除定時(shí)任務(wù)"""
if scheduler.get_job(job_id):
scheduler.remove_job(job_id)
return f"已移除任務(wù): {job_id}"
return "任務(wù)不存在"
if __name__ == '__main__':
app.run(debug=True)
代碼解釋
1. 依賴安裝
pip install flask apscheduler
2. 核心組件
BackgroundScheduler:后臺(tái)線程調(diào)度器,不會(huì)阻塞主線程
SQLAlchemyJobStore:任務(wù)持久化存儲(chǔ),使用SQLite數(shù)據(jù)庫(kù)
add_job():添加任務(wù)的核心方法
3. 任務(wù)類型
Cron任務(wù)(定時(shí)執(zhí)行):
trigger='cron', hour=9, minute=0 # 每天9:00執(zhí)行
間隔任務(wù)(周期性執(zhí)行):
trigger='interval', minutes=5 # 每5分鐘執(zhí)行
一次性任務(wù):
trigger='date', run_date=datetime.now() + timedelta(seconds=10)
4. 任務(wù)管理
動(dòng)態(tài)添加任務(wù):通過(guò)路由 /add_job/<minutes> 添加新任務(wù)
任務(wù)列表查看:通過(guò)路由 /jobs 查看所有任務(wù)
任務(wù)刪除:通過(guò)路由 /remove_job/<job_id> 刪除任務(wù)
5. 持久化存儲(chǔ)
使用SQLite數(shù)據(jù)庫(kù)存儲(chǔ)任務(wù)信息,確保服務(wù)器重啟后任務(wù)不丟失:
jobstores={
'default': SQLAlchemyJobStore(url='sqlite:///jobs.db')
}
生產(chǎn)環(huán)境部署注意事項(xiàng)
1. 多進(jìn)程問(wèn)題解決方案
當(dāng)使用Gunicorn等WSGI服務(wù)器時(shí)(多worker進(jìn)程),每個(gè)worker都會(huì)啟動(dòng)調(diào)度器實(shí)例,導(dǎo)致任務(wù)重復(fù)執(zhí)行。
解決方案:
# 在應(yīng)用工廠函數(shù)中初始化調(diào)度器
def create_app():
app = Flask(__name__)
if os.environ.get('WERKZEUG_RUN_MAIN') == 'true' or not app.debug:
# 確保只在主進(jìn)程中初始化調(diào)度器
scheduler = BackgroundScheduler(daemon=True)
scheduler.start()
# 添加任務(wù)...
return app
2. 替代方案:Celery
對(duì)于分布式環(huán)境,推薦使用Celery:
# Celery配置示例
from celery import Celery
from celery.schedules import crontab
app = Celery('tasks', broker='redis://localhost:6379/0')
@app.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
# 每10分鐘執(zhí)行
sender.add_periodic_task(600, task1.s(), name='每10分鐘任務(wù)')
# 每天午夜執(zhí)行
sender.add_periodic_task(
crontab(hour=0, minute=0),
task2.s(),
name='每日午夜任務(wù)'
)
@app.task
def task1():
print("執(zhí)行每10分鐘任務(wù)")
@app.task
def task2():
print("執(zhí)行每日任務(wù)")
3. 錯(cuò)誤處理與日志
def job_with_error_handling():
try:
# 業(yè)務(wù)代碼
pass
except Exception as e:
app.logger.error(f"任務(wù)執(zhí)行失敗: {str(e)}")
# 發(fā)送警報(bào)郵件
send_alert_email(f"任務(wù)失敗: {str(e)}")
def send_alert_email(message):
# 實(shí)現(xiàn)郵件發(fā)送邏輯
pass
方案對(duì)比
| 特性 | APScheduler | Celery |
|---|---|---|
| 復(fù)雜度 | 簡(jiǎn)單 | 中等 |
| 分布式支持 | 有限 | 優(yōu)秀 |
| 持久化 | 需要配置 | 內(nèi)置 |
| 多進(jìn)程支持 | 需要特殊處理 | 原生支持 |
| 任務(wù)隊(duì)列 | 無(wú) | 有 |
| 適用場(chǎng)景 | 單機(jī)/簡(jiǎn)單任務(wù) | 分布式/復(fù)雜任務(wù) |
到此這篇關(guān)于Python Flask實(shí)現(xiàn)定時(shí)任務(wù)的不同方法詳解的文章就介紹到這了,更多相關(guān)Flask定時(shí)任務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之
相關(guān)文章
小白入門篇使用Python搭建點(diǎn)擊率預(yù)估模型
本文將從零開(kāi)始,僅僅利用基礎(chǔ)的numpy庫(kù),使用Python實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)(或者說(shuō)是簡(jiǎn)易的LR,因?yàn)長(zhǎng)R就是一個(gè)單層的神經(jīng)網(wǎng)絡(luò)),解決一個(gè)點(diǎn)擊率預(yù)估的問(wèn)題。感興趣的朋友跟隨小白一起看看吧2018-10-10
Python新手學(xué)習(xí)函數(shù)默認(rèn)參數(shù)設(shè)置
在本篇文章里小編給大家分享的是關(guān)于Python新手學(xué)習(xí)函數(shù)默認(rèn)參數(shù)設(shè)置的相關(guān)知識(shí)點(diǎn),需要的朋友們可以參考下。2020-06-06
python linecache 處理固定格式文本數(shù)據(jù)的方法
今天小編就為大家分享一篇python linecache 處理固定格式文本數(shù)據(jù)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01
Python通過(guò)OpenPyXL處理Excel的完整教程
OpenPyXL是一個(gè)強(qiáng)大的Python庫(kù),用于處理Excel文件,允許讀取、編輯和創(chuàng)建Excel工作簿和工作表,本文將詳細(xì)介紹OpenPyXL的各種功能,希望對(duì)大家有所幫助2023-11-11
基于Python實(shí)現(xiàn)大文件分割和命名腳本過(guò)程解析
這篇文章主要介紹了基于Python實(shí)現(xiàn)大文件分割和命名腳本過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09

