天天看點

[轉]Python定時任務架構APScheduler

        安裝過程很簡單,可以基于easy_install和源碼。

easy_install apscheduler  

python setup.py install  

        APScheduler是程序内的排程器,可以定時觸發具體的函數,并且可以通路應用的所有變量和函數。在web應用中通過APScheduler實作定時任務是很友善的。下面看例子:

from apscheduler.scheduler import Scheduler  

schedudler = Scheduler(daemonic = False)  

@schedudler.cron_schedule(second='*', day_of_week='0-4', hour='9-12,13-15')  

def quote_send_sh_job():  

    print 'a simple cron job start at', datetime.datetime.now()  

schedudler.start()  

        上面通過裝飾器定義了cron job,可以通過函數scheduler.add_cron_job添加,用裝飾器更友善。Scheduler構造函數中傳入daemonic參數,表示執行線程是非守護的,在Schduler的文檔中推薦使用非守護線程:

Jobs are always executed in non-daemonic threads.  

        在添加job時還有一個比較重要的參數max_instances,指定一個job的并發執行個體數,預設值是1。預設情況下,如果一個job準備執行,但是該job的前一個執行個體尚未執行完,則後一個job會失敗,可以通過這個參數來改變這種情況。

        APScheduler提供了jobstore用于存儲job的執行資訊,預設使用的是RAMJobStore,還提供了 SQLAlchemyJobStore、ShelveJobStore和MongoDBJobStore。APScheduler允許同時使用多個 jobstore,通過别名(alias)區分,在添加job時需要指定具體的jobstore的别名,否則使用的是别名是default的 jobstore,即RAMJobStore。下面以MongoDBJobStore舉例說明。

import pymongo  

from apscheduler.jobstores.mongodb_store import MongoDBJobStore  

import time  

sched = Scheduler(daemonic = False)  

mongo = pymongo.Connection(host='127.0.0.1', port=27017)  

store = MongoDBJobStore(connection=mongo)  

sched.add_jobstore(store, 'mongo')        # 别名是mongo  

@sched.cron_schedule(second='*', day_of_week='0-4', hour='9-12,13-15', jobstore='mongo')        # 向别名為mongo的jobstore添加job  

def job():  

        print 'a job'  

        time.sleep(1)  

sched.start()  

        注意start必須在添加job動作之後調用,否則會抛錯。預設會把job資訊儲存在apscheduler資料庫下的jobs表:

> db.jobs.findOne()  

{  

        "_id" : ObjectId("502202d1443c1557fa8b8d66"),  

        "runs" : 20,  

        "name" : "job",  

        "misfire_grace_time" : 1,  

        "coalesce" : true,  

        "args" : BinData(0,"gAJdcQEu"),  

        "next_run_time" : ISODate("2012-08-08T14:10:46Z"),  

        "max_instances" : 1,  

        "max_runs" : null,  

        "trigger" : BinData(0,"gAJjYXBzY2hlZHVsZXIudHJpZ2dlcnMuY3JvbgpDcm9uVHJpZ2dlcgpxASmBcQJ9cQMoVQZmaWVsZHNxBF1xBShjYXBzY2hlZHVsZXIudHJpZ2dlcnMuY3Jvbi5maWVsZHMKQmFzZUZpZWxkCnEGKYFxB31xCChVCmlzX2RlZmF1bHRxCYhVC2V4cHJlc3Npb25zcQpdcQtjYXBzY2hlZHVsZXIudHJpZ2dlcnMuY3Jvbi5leHByZXNzaW9ucwpBbGxFeHByZXNzaW9uCnEMKYFxDX1xDlUEc3RlcHEPTnNiYVUEbmFtZXEQVQR5ZWFycRF1YmgGKYFxEn1xEyhoCYhoCl1xFGgMKYFxFX1xFmgPTnNiYWgQVQVtb250aHEXdWJjYXBzY2hlZHVsZXIudHJpZ2dlcnMuY3Jvbi5maWVsZHMKRGF5T2ZNb250aEZpZWxkCnEYKYFxGX1xGihoCYhoCl1xG2gMKYFxHH1xHWgPTnNiYWgQVQNkYXlxHnViY2Fwc2NoZWR1bGVyLnRyaWdnZXJzLmNyb24uZmllbGRzCldlZWtGaWVsZApxHymBcSB9cSEoaAmIaApdcSJoDCmBcSN9cSRoD05zYmFoEFUEd2Vla3EldWJjYXBzY2hlZHVsZXIudHJpZ2dlcnMuY3Jvbi5maWVsZHMKRGF5T2ZXZWVrRmllbGQKcSYpgXEnfXEoKGgJiWgKXXEpY2Fwc2NoZWR1bGVyLnRyaWdnZXJzLmNyb24uZXhwcmVzc2lvbnMKUmFuZ2VFeHByZXNzaW9uCnEqKYFxK31xLChoD05VBGxhc3RxLUsEVQVmaXJzdHEuSwB1YmFoEFULZGF5X29mX3dlZWtxL3ViaAYpgXEwfXExKGgJiWgKXXEyKGgqKYFxM31xNChoD05oLUsMaC5LCXViaCopgXE1fXE2KGgPTmgtSw9oLksNdWJlaBBVBGhvdXJxN3ViaAYpgXE4fXE5KGgJiGgKXXE6aAwpgXE7fXE8aA9Oc2JhaBBVBm1pbnV0ZXE9dWJoBimBcT59cT8oaAmJaApdcUBoDCmBcUF9cUJoD05zYmFoEFUGc2Vjb25kcUN1YmVVCnN0YXJ0X2RhdGVxRE51Yi4="),  

        "func_ref" : "__main__:job",  

        "kwargs" : BinData(0,"gAJ9cQEu")  

}  

        上面就是存儲的具體資訊。

        當job抛出異常時,APScheduler會默默的把他吞掉,不提供任何提示,這不是一種好的實踐,我們必須知曉程式的任何差錯。APScheduler提供注冊listener,可以監聽一些事件,包括:job抛出異常、job沒有來得及執行等。

Constant

Event class

Triggered when...

EVENT_SCHEDULER_START

SchedulerEvent

The scheduler is started

EVENT_SCHEDULER_SHUTDOWN

The scheduler is shut down

EVENT_JOBSTORE_ADDED

JobStoreEvent

A job store is added to the scheduler

EVENT_JOBSTORE_REMOVED

A job store is removed from the scheduler

EVENT_JOBSTORE_JOB_ADDED

A job is added to a job store

EVENT_JOBSTORE_JOB_REMOVED

A job is removed from a job store

EVENT_JOB_EXECUTED

JobEvent

A job is executed successfully

EVENT_JOB_ERROR

A job raised an exception during execution

EVENT_JOB_MISSED

A job’s execution time is missed

        看下面的例子,監聽異常和miss事件,這裡用logging子產品列印日志,logger.exception()可以列印出異常堆棧資訊。

def err_listener(ev):  

    err_logger = logging.getLogger('schedErrJob')  

    if ev.exception:  

        err_logger.exception('%s error.', str(ev.job))  

    else:  

        err_logger.info('%s miss', str(ev.job))  

schedudler.add_listener(err_listener, apscheduler.events.EVENT_JOB_ERROR | apscheduler.events.EVENT_JOB_MISSED)  

        事件的屬性包括:

job – the job instance in question

scheduled_run_time – the time when the job was scheduled to be run

retval – the return value of the successfully executed job

exception – the exception raised by the job

traceback – the traceback object associated with the exception

        最後,需要注意一點當job不以daemon模式運作時,并且APScheduler也不是daemon的,那麼在關閉腳本時,Ctrl + C是不奏效的,必須kill才可以。可以通過指令實作關閉腳本: