最近,想要實(shí)現(xiàn)一個(gè)功能,就是添加定時(shí)任務(wù)的同時(shí)記錄其任務(wù)信息到數(shù)據(jù)庫中胰坟,可以通過接口查看設(shè)定了哪些定時(shí)任務(wù),經(jīng)過調(diào)研泞辐,發(fā)現(xiàn)大家公認(rèn)的Python最好用的定時(shí)任務(wù)框架是APScheduler笔横。
Python Scheduler(APScheduler)是一個(gè)Python庫竞滓,它允許您安排稍后要執(zhí)行的Python代碼,只需一次或定期執(zhí)行吹缔。 您可以在您的同時(shí)添加新的作業(yè)或刪除舊的舊作業(yè)商佑。 如果在數(shù)據(jù)庫中存儲(chǔ)工作,他們還將存活調(diào)度程序重新啟動(dòng)并保持狀態(tài)厢塘。 調(diào)度程序重新啟動(dòng)時(shí)茶没,它將運(yùn)行它在脫機(jī)時(shí)應(yīng)該運(yùn)行的所有作業(yè)
在網(wǎng)上找了一堆資料,包括官方教程晚碾,但對(duì)于和MySQL協(xié)作使用的方面語焉不詳抓半,因此,這里做個(gè)記錄格嘁。
項(xiàng)目使用的環(huán)境如下:
- Python 3.7
- MySQL
- APScheduler
- Navicat for MySQL
APScheduler Startup
首先,安裝APScheduler:
pip install apscheduler
然后就可以編寫簡(jiǎn)單的demo了:
from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime
def job():
# 輸出當(dāng)前時(shí)間
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
# BlockingScheduler
scheduler = BlockingScheduler()
scheduler.add_job(job, 'cron', day_of_week='0-4', hour=6, minute=30)
這個(gè)demo表示每周的星期一到星期五的六點(diǎn)半報(bào)時(shí)
APScheduler基礎(chǔ)教程
具體見大佬2的博客讥蔽,這里不做贅述
這里總結(jié)一下常用的任務(wù)模式。
interval間隔時(shí)間任務(wù)
即每隔一段時(shí)間執(zhí)行一次画机,可能的字段為:
字段 | 值類型 | 說明 |
---|---|---|
weeks | int | number of weeks to wait |
days | int | number of days to wait |
hours | int | number of hours to wait |
minutes | int | number of minutes to wait |
seconds | int | number of seconds to wait |
start_date | datetime/str | starting point for the interval calculation |
end_date | datetime/str | latest possible date/time to trigger on |
timezone | datetime.tzinfo/str | time zone to use for the date/time calculations |
例子:
#表示每隔3秒執(zhí)行一次任務(wù)
scheduler.add_job(tok, 'interval', seconds=3)
#表示每隔3天17時(shí)19分07秒執(zhí)行一次任務(wù)
sched.add_job(my_job, 'interval',days = 03,hours = 17,minutes = 19,seconds = 07)
date定點(diǎn)任務(wù)
即在某個(gè)時(shí)刻運(yùn)行冶伞,但僅執(zhí)行一次,可能的字段為:
字段 | 值類型 | 說明 |
---|---|---|
run_date | datetime/str | the date/time to run the job at -(任務(wù)開始的時(shí)間) |
timezone | datetime.tzinfo/str | time zone for run_date if it doesn’t have one already |
栗子:
# 任務(wù)將在2009年11月6日00:00:00執(zhí)行
sched.add_job(my_job, 'date', run_date=date(2009, 11, 6), args=['text'])
# 任務(wù)將在2009年11月6日16:30:05執(zhí)行
sched.add_job(my_job, 'date', run_date=datetime(2009, 11, 6, 16, 30, 5), args=['text'])
cron某一時(shí)刻任務(wù)
可能的字段為:
字段 | 值類型 | 值 | 說明 |
---|---|---|---|
year | int/str | XXXX | 表示四位數(shù)的年份步氏,如2008年 |
month | int/str | 1-12 | 表示取值范圍為1-12月 |
day | int/str | 1-31 | 表示取值范圍為1-31日 |
week | int/str | 1-53 | 格里歷2006年12月31日可以寫成2006年-W52-7 擴(kuò)展形式或2006W527 緊湊形式 |
day_of_week | int/str | 0-6 或 mon,tue,wed,thu,fri,sat,sun | 表示一周中的第幾天响禽,既可以用0-6表示也可以用其英語縮寫表示 |
hour | int/str | 0-23 | 表示取值范圍為0-23時(shí) |
minute | int/str | 0-59 | 表示取值范圍為0-59分 |
second | int/str | 0-59 | 表示取值范圍為0-59秒 |
start_date | datetime/str | XXXX-XX-XX hh:mm:ss | 表示開始時(shí)間 |
end_date | datetime/str | XXXX-XX-XX hh:mm:ss | 表示結(jié)束時(shí)間 |
timezone | datetime.tzinfo/str | time zone to use for the date/time calculations | 表示時(shí)區(qū)取值 |
其中,int/str
表示參數(shù)既可以是int類型荚醒,也可以是str類型芋类;datetime/str
表示參數(shù)既可以是datetime類型,也可以是str類型
例子:
#表示2017年3月22日17時(shí)19分07秒執(zhí)行該程序
sched.add_job(my_job, 'cron', year=2017,month = 03,day = 22,hour = 17,minute = 19,second = 07)
#表示任務(wù)在6,7,8,11,12月份的第三個(gè)星期五的00:00,01:00,02:00,03:00 執(zhí)行該程序
sched.add_job(my_job, 'cron', month='6-8,11-12', day='3rd fri', hour='0-3')
#表示從星期一到星期五5:30(AM)直到2014-05-30 00:00:00
sched.add_job(my_job(), 'cron', day_of_week='mon-fri', hour=5, minute=30,end_date='2014-05-30')
#表示每5秒執(zhí)行該程序一次界阁,相當(dāng)于interval 間隔調(diào)度中seconds = 5
sched.add_job(my_job, 'cron',second = '*/5') 作者:燕洼仙草 https://www.bilibili.com/read/cv7868920/ 出處:bilibili
APScheduler + MySQL
不過我們肯定并不滿足于實(shí)現(xiàn)一個(gè)小小的demo侯繁。
如果我們想要連接MySQL
實(shí)現(xiàn)持久化存儲(chǔ)應(yīng)該怎么做呢?
這里需要配置調(diào)度器:
scheduler = BackgroundScheduler({
'apscheduler.jobstores.default': {
'type': 'sqlalchemy',
'url': 'mysql+pymysql://username:password@127.0.0.1:3306/dbname?charset=utf8',
'tablename': 'api_job'
},
'apscheduler.executors.default': {
'class': 'apscheduler.executors.pool:ThreadPoolExecutor',
'max_workers': '20'
},
'apscheduler.executors.processpool': {
'type': 'processpool',
'max_workers': '10'
},
'apscheduler.job_defaults.coalesce': 'false',
'apscheduler.job_defaults.max_instances': '10',
'apscheduler.timezone': 'UTC',
})
其中泡躯,apscheduler.jobstores.default
字段表示存儲(chǔ)器的配置贮竟,字段說明如下:
-
type
表示數(shù)據(jù)庫的類型,MySQL
屬于SQLAlchemy
较剃,因此這里值填寫sqlalchemy
-
url
表示存儲(chǔ)器訪問呢的地址咕别,其中的這些字段需要配置:-
username
為你的數(shù)據(jù)庫的用戶名 -
password
為對(duì)應(yīng)的賬號(hào)的密碼 -
dbname
為數(shù)據(jù)庫名稱
-
-
tablename
表示將定時(shí)任務(wù)數(shù)據(jù)存儲(chǔ)的表名
然后就可以使用配置好的scheduler
添加任務(wù)了:
scheduler.add_job(tok, 'interval', seconds=3, id=job_id, coalesce=True, replace_existing=True)
其中id
表示任務(wù)的唯一標(biāo)識(shí)符,coalesce
表示忽略服務(wù)器宕機(jī)時(shí)間段內(nèi)的任務(wù)執(zhí)行(否則就會(huì)出現(xiàn)服務(wù)器恢復(fù)之后一下子執(zhí)行多次任務(wù)的情況)写穴,replace_existing
表示如果有重名的任務(wù)惰拱,直接覆蓋
添加任務(wù)后就可以看到數(shù)據(jù)庫多出了內(nèi)容:
這里使用了中文字符串作為id,可以語義地表示任務(wù)
然鵝啊送,要想任務(wù)存儲(chǔ)其他信息怎么辦偿短,這里思來想去欣孤,決定在數(shù)據(jù)庫創(chuàng)建一個(gè)新的表,用于記錄任務(wù)的詳細(xì)信息翔冀,方便后續(xù)查看导街,每次添加任務(wù)時(shí)往該表插值即可,刪除任務(wù)時(shí)也刪除對(duì)應(yīng)的數(shù)據(jù)纤子,由此實(shí)現(xiàn)任務(wù)數(shù)據(jù)的同步搬瑰。
不過需要注意的是,在添加重復(fù)名稱的定時(shí)任務(wù)時(shí)控硼,設(shè)置replace_existing=True
泽论,直接覆蓋已有的任務(wù);相應(yīng)地卡乾,在對(duì)其任務(wù)信息表翼悴,我們采用REPLACE
替代INSERT
語句來執(zhí)行插入操作,其使用方法和INSERT
完全一樣幔妨,但如果表中有重復(fù)的數(shù)據(jù)鹦赎,則會(huì)直接覆蓋,其優(yōu)勢(shì)不言而喻误堡。由此古话,實(shí)現(xiàn)了協(xié)同操作。
其數(shù)字孿生任務(wù)信息表的字段可為: