Python Flask實(shí)現(xiàn)定時任務(wù)的不同方法詳解
在 Flask 中實(shí)現(xiàn)定時任務(wù),最常用的方法是使用 APScheduler 庫(Advanced Python Scheduler)。下面我將提供一個完整的解決方案,包含代碼實(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
)
# 定義定時任務(wù)函數(shù)
def daily_report():
"""每天上午9點(diǎn)執(zhí)行的日報(bào)任務(wù)"""
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"[日報(bào)] 執(zhí)行時間: {current_time}")
# 這里添加實(shí)際的日報(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í)行時間: {current_time}")
# 這里添加實(shí)際的任務(wù)邏輯
def on_startup():
"""應(yīng)用啟動時添加定時任務(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)用啟動后10秒執(zhí)行)
scheduler.add_job(
id='startup_check',
func=lambda: print("應(yīng)用啟動完成!"),
trigger='date',
run_date=datetime.now() + timedelta(seconds=10)
)
# 啟動調(diào)度器
if not scheduler.running:
scheduler.start()
on_startup()
@app.route('/')
def home():
return """
<h1>Flask 定時任務(wù)示例</h1>
<p>已啟動的定時任務(wù):</p>
<ul>
<li>日報(bào)任務(wù):每天9:00執(zhí)行</li>
<li>5分鐘任務(wù):每5分鐘執(zhí)行一次</li>
</ul>
<p>查看控制臺輸出獲取執(zhí)行詳情</p>
"""
@app.route('/jobs')
def list_jobs():
"""查看當(dāng)前所有定時任務(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):
"""動態(tài)添加定時任務(wù)"""
try:
minutes = int(minutes)
job_id = f"dynamic_job_{minutes}min"
scheduler.add_job(
id=job_id,
func=lambda: print(f"動態(tài)添加的任務(wù) - 每 {minutes} 分鐘執(zhí)行一次"),
trigger='interval',
minutes=minutes,
replace_existing=True
)
return f"成功添加每 {minutes} 分鐘執(zhí)行的任務(wù)!"
except ValueError:
return "參數(shù)錯誤,請輸入有效的分鐘數(shù)"
@app.route('/remove_job/<job_id>')
def remove_job(job_id):
"""移除定時任務(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:后臺線程調(diào)度器,不會阻塞主線程
SQLAlchemyJobStore:任務(wù)持久化存儲,使用SQLite數(shù)據(jù)庫
add_job():添加任務(wù)的核心方法
3. 任務(wù)類型
Cron任務(wù)(定時執(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ù)管理
動態(tài)添加任務(wù):通過路由 /add_job/<minutes> 添加新任務(wù)
任務(wù)列表查看:通過路由 /jobs 查看所有任務(wù)
任務(wù)刪除:通過路由 /remove_job/<job_id> 刪除任務(wù)
5. 持久化存儲
使用SQLite數(shù)據(jù)庫存儲任務(wù)信息,確保服務(wù)器重啟后任務(wù)不丟失:
jobstores={
'default': SQLAlchemyJobStore(url='sqlite:///jobs.db')
}
生產(chǎn)環(huán)境部署注意事項(xiàng)
1. 多進(jìn)程問題解決方案
當(dāng)使用Gunicorn等WSGI服務(wù)器時(多worker進(jìn)程),每個worker都會啟動調(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
對于分布式環(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. 錯誤處理與日志
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
方案對比
| 特性 | APScheduler | Celery |
|---|---|---|
| 復(fù)雜度 | 簡單 | 中等 |
| 分布式支持 | 有限 | 優(yōu)秀 |
| 持久化 | 需要配置 | 內(nèi)置 |
| 多進(jìn)程支持 | 需要特殊處理 | 原生支持 |
| 任務(wù)隊(duì)列 | 無 | 有 |
| 適用場景 | 單機(jī)/簡單任務(wù) | 分布式/復(fù)雜任務(wù) |
到此這篇關(guān)于Python Flask實(shí)現(xiàn)定時任務(wù)的不同方法詳解的文章就介紹到這了,更多相關(guān)Flask定時任務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之
相關(guān)文章
Python不要再使用while死循環(huán),定時器代替效果更佳
在python開發(fā)的過程中,經(jīng)常見到小伙伴直接使用while True的死循環(huán)+sleep的方式來保存程序的一直運(yùn)行。這種方式雖然能達(dá)到效果,但是說不定什么時候就直接崩潰了,其實(shí)使用定時器效果也不錯哦2023-03-03
基于Python編寫一個簡單的服務(wù)注冊發(fā)現(xiàn)服務(wù)器
我們都知道有很多的非常著名的注冊服務(wù)器,例如:?Consul、ZooKeeper、etcd,甚至借助于redis完成服務(wù)注冊發(fā)現(xiàn)。但是本篇文章我們將使用python?socket寫一個非常簡單的服務(wù)注冊發(fā)現(xiàn)服務(wù)器,感興趣的可以了解一下2023-04-04
opencv+python識別七段數(shù)碼顯示器的數(shù)字(數(shù)字識別)
本文主要介紹了opencv+python識別七段數(shù)碼顯示器的數(shù)字(數(shù)字識別),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
python 定時器,實(shí)現(xiàn)每天凌晨3點(diǎn)執(zhí)行的方法
今天小編就為大家分享一篇python 定時器,實(shí)現(xiàn)每天凌晨3點(diǎn)執(zhí)行的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-02-02
基于Python實(shí)現(xiàn)一個簡單的銀行轉(zhuǎn)賬操作
這篇文章主要介紹了基于Python實(shí)現(xiàn)一個簡單的銀行轉(zhuǎn)賬操作的相關(guān)資料,需要的朋友可以參考下2016-03-03
Python實(shí)現(xiàn)Event回調(diào)機(jī)制的方法
今天小編就為大家分享一篇Python實(shí)現(xiàn)Event回調(diào)機(jī)制的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-02-02
Pytorch 神經(jīng)網(wǎng)絡(luò)—自定義數(shù)據(jù)集上實(shí)現(xiàn)教程
今天小編就為大家分享一篇Pytorch 神經(jīng)網(wǎng)絡(luò)—自定義數(shù)據(jù)集上實(shí)現(xiàn)教程,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-01-01

