flask_apscheduler 定時任務(wù)踩坑記錄

背景

由于需要再flask做一個定時任務(wù),然后發(fā)現(xiàn)了這個庫flask_apscheduler.使用很簡單,就是可能由于某種情況,會有一些意外,下面是我的使用記錄。

首先按照官方文檔跑一個示例
from flask import Flask
from flask_apscheduler import APScheduler


class Config(object):
    JOBS = [
        {
            'id': 'job1',
            'func': 'jobs:job1',
            'args': (1, 2),
            'trigger': 'interval',
            'seconds': 10
        }
    ]

    SCHEDULER_API_ENABLED = True


def job1(a, b):
    print(str(a) + ' ' + str(b))


if __name__ == '__main__':
    app = Flask(__name__)
    app.config.from_object(Config())

    scheduler = APScheduler()
    # it is also possible to enable the API directly
    # scheduler.api_enabled = True
    scheduler.init_app(app)
    scheduler.start()

    app.run()
  • 'func': 'jobs:job1', 配置文件中這一行,代表任務(wù)。jobs代表這個文件名。job1是自己創(chuàng)建的任務(wù)函數(shù)。

ok,這里沒有任何問題

問題1:在實際項目中,不可能都放在同一個文件下,創(chuàng)建一個任務(wù)時,找不到這個任務(wù)

如,我定義一個start函數(shù),用于執(zhí)行定時任務(wù),這個start在app.models.ali路徑下。問題原因是:'func': 'app:start'配置格式等有誤,正確應(yīng)該按照自己任務(wù)文件的實際路徑,格式為:'func': 'app:models.ali.start',如下:

class Config:

    JOBS = [
        {
            'id': 'job1',
            'func': 'app:models.ali.start',
            'trigger': 'cron',
            'day_of_week': 'mon-fri',
            'second': 1,
            'hour': 9,
            'minute': 30
        }
    ]

    SCHEDULER_API_ENABLED = True
問題2:在model文件里使用SQLAlchemy時,報錯類似:No application found.flask-apsched Either work inside a view function or pus,也就是無法在任務(wù)函數(shù)中使用SQLAlchemy。解決辦法:
  • app的__init__.py關(guān)鍵代碼:
from flask_apscheduler import APScheduler
scheduler = APScheduler()

def create_app(config_name):
    app = Flask(__name__, template_folder='templates')
    app.config.from_object(config.get(config_name) or config['default'])
    ...
    scheduler.init_app(app)
    scheduler.start()
    return app

  • 然后我的任務(wù)start在app.models.ali路徑下,需要在ali.py下:
from app import scheduler

def start():
    with scheduler.app.app_context():
        results = AliServers.query.all()
        ···

添加上下文后,就可以使用AliServers.query.all()這種操作了。

問題3:

本機開發(fā)環(huán)境下,一切正常,然后部署到服務(wù)器上,出錯:

Traceback (most recent call last):
  File "test.py", line 29, in <module>
    scheduler = APScheduler()
  File "/root/.local/share/virtualenvs/flask-fUo2koNK/lib/python3.6/site-packages/flask_apscheduler/scheduler.py", line 36, in __init__
    self._scheduler = scheduler or BackgroundScheduler()
  File "/root/.local/share/virtualenvs/flask-fUo2koNK/lib/python3.6/site-packages/apscheduler/schedulers/base.py", line 87, in __init__
    self.configure(gconfig, **options)
  File "/root/.local/share/virtualenvs/flask-fUo2koNK/lib/python3.6/site-packages/apscheduler/schedulers/base.py", line 126, in configure
    self._configure(config)
  File "/root/.local/share/virtualenvs/flask-fUo2koNK/lib/python3.6/site-packages/apscheduler/schedulers/background.py", line 29, in _configure
    super(BackgroundScheduler, self)._configure(config)
  File "/root/.local/share/virtualenvs/flask-fUo2koNK/lib/python3.6/site-packages/apscheduler/schedulers/base.py", line 697, in _configure
    self.timezone = astimezone(config.pop('timezone', None)) or get_localzone()
  File "/root/.local/share/virtualenvs/flask-fUo2koNK/lib/python3.6/site-packages/tzlocal/unix.py", line 165, in get_localzone
    _cache_tz = _get_localzone()
  File "/root/.local/share/virtualenvs/flask-fUo2koNK/lib/python3.6/site-packages/tzlocal/unix.py", line 90, in _get_localzone
    utils.assert_tz_offset(tz)
  File "/root/.local/share/virtualenvs/flask-fUo2koNK/lib/python3.6/site-packages/tzlocal/utils.py", line 38, in assert_tz_offset
    raise ValueError(msg)
ValueError: Timezone offset does not match system offset: 28800 != -14400. Please, check your config files.

根據(jù)錯誤信息查看源碼,解決辦法:
主要是兩個地方:
首先查看服務(wù)器時區(qū)是上海,然后需要修改兩個地方:

  • 在配置文件中添加SCHEDULER_TIMEZONE = 'Asia/Shanghai',即:
class Config:

    JOBS = [
        {
            'id': 'job1',
            'func': 'app:models.ali.start',
            'trigger': 'cron',
            'day_of_week': 'mon-fri',
            'second': 1,
            'hour': 9,
            'minute': 30
        }
    ]
    SCHEDULER_TIMEZONE = 'Asia/Shanghai'
    SCHEDULER_API_ENABLED = True

然后在app的__init__.py下,添加BackgroundScheduler(timezone="Asia/Shanghai")

from flask_apscheduler import APScheduler
from apscheduler.schedulers.background import BackgroundScheduler 
scheduler = APScheduler(BackgroundScheduler(timezone="Asia/Shanghai"))

def create_app(config_name):
    app = Flask(__name__, template_folder='templates')
    app.config.from_object(config.get(config_name) or config['default'])
    ...

    scheduler.init_app(app)
    scheduler.start()
    return app

原因是:時區(qū)會被解析兩次,如果沒有加時區(qū),就會調(diào)用默認的self.timezone = astimezone(config.pop('timezone', None)) or get_localzone(),由于時區(qū)與系統(tǒng)不匹配,會報錯。當(dāng)然這個錯誤并不是每個機器都有,正巧,這臺服務(wù)器的時區(qū)與系統(tǒng)偏移不一致,導(dǎo)致出現(xiàn)這個錯誤。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容