安排一个函数在Flask上每小时运行一次

时间:2014-01-19 07:31:48

标签: python flask

我有一个Flask网络托管,无法访问cron命令。 我怎样才能每小时执行一些Python函数?

11 个答案:

答案 0 :(得分:66)

您可以使用BackgroundScheduler()包中的APScheduler(v3.5.3):

import time
import atexit

from apscheduler.schedulers.background import BackgroundScheduler


def print_date_time():
    print(time.strftime("%A, %d. %B %Y %I:%M:%S %p"))


scheduler = BackgroundScheduler()
scheduler.add_job(func=print_date_time, trigger="interval", seconds=3)
scheduler.start()

# Shut down the scheduler when exiting the app
atexit.register(lambda: scheduler.shutdown())

请注意,当Flask处于调试模式时,将启动其中两个调度程序。有关详细信息,请查看this问题。

答案 1 :(得分:44)

您可以在Flask应用程序中使用APScheduler并通过其界面运行您的作业:

import atexit

# v2.x version - see https://stackoverflow.com/a/38501429/135978
# for the 3.x version
from apscheduler.scheduler import Scheduler
from flask import Flask

app = Flask(__name__)

cron = Scheduler(daemon=True)
# Explicitly kick off the background thread
cron.start()

@cron.interval_schedule(hours=1)
def job_function():
    # Do your work here


# Shutdown your cron thread if the web process is stopped
atexit.register(lambda: cron.shutdown(wait=False))

if __name__ == '__main__':
    app.run()

答案 2 :(得分:23)

我对应用程序调度程序的概念有点新意,但是我在APScheduler v3.3.1找到了它,它有点不同。我相信对于最新版本,包装结构,类名等已经改变,所以我在这里提出了一个我最近制作的新解决方案,与基本的Flask应用程序集成:

#!/usr/bin/python3
""" Demonstrating Flask, using APScheduler. """

from apscheduler.schedulers.background import BackgroundScheduler
from flask import Flask

def sensor():
    """ Function for test purposes. """
    print("Scheduler is alive!")

sched = BackgroundScheduler(daemon=True)
sched.add_job(sensor,'interval',minutes=60)
sched.start()

app = Flask(__name__)

@app.route("/home")
def home():
    """ Function for test purposes. """
    return "Welcome Home :) !"

if __name__ == "__main__":
    app.run()

我还要留下这个要点here,如果有人对此示例的更新感兴趣。

以下是一些参考资料,供将来阅读:

答案 3 :(得分:9)

您可以尝试使用APScheduler's BackgroundScheduler将间隔作业集成到Flask应用中。以下是使用蓝图和应用工厂( init .py)的示例:

from datetime import datetime

# import BackgroundScheduler
from apscheduler.schedulers.background import BackgroundScheduler
from flask import Flask

from webapp.models.main import db 
from webapp.controllers.main import main_blueprint    

# define the job
def hello_job():
    print('Hello Job! The time is: %s' % datetime.now())

def create_app(object_name):
    app = Flask(__name__)
    app.config.from_object(object_name)
    db.init_app(app)
    app.register_blueprint(main_blueprint)
    # init BackgroundScheduler job
    scheduler = BackgroundScheduler()
    # in your case you could change seconds to hours
    scheduler.add_job(hello_job, trigger='interval', seconds=3)
    scheduler.start()

    try:
        # To keep the main thread alive
        return app
    except:
        # shutdown if app occurs except 
        scheduler.shutdown()

希望有所帮助:)

参考:

  1. https://github.com/agronholm/apscheduler/blob/master/examples/schedulers/background.py

答案 4 :(得分:6)

另一种选择可能是使用Flask-APScheduler,它可以很好地与Flask一起使用,例如:

  • 从Flask配置
  • 加载调度程序配置
  • 从Flask配置
  • 加载作业定义

此处提供更多信息:

https://pypi.python.org/pypi/Flask-APScheduler

答案 5 :(得分:3)

一个完整的示例,使用时间表和多处理功能,具有on_off控制和run_job()参数 返回码经过简化,时间间隔设置为10秒,更改为every(2).hour.do() 2小时。日程安排非常令人印象深刻,它不会漂移,而且我从未在日程安排中看到超过100毫秒的时间。使用多处理而不是线程,因为它具有终止方法。

#!/usr/bin/env python3

import schedule
import time
import datetime
import uuid

from flask import Flask, request
from multiprocessing import Process

app = Flask(__name__)
t = None
job_timer = None

def run_job(id):
    """ sample job with parameter """
    global job_timer
    print("timer job id={}".format(id))
    print("timer: {:.4f}sec".format(time.time() - job_timer))
    job_timer = time.time()

def run_schedule():
    """ infinite loop for schedule """
    global job_timer
    job_timer = time.time()
    while 1:
        schedule.run_pending()
        time.sleep(1)

@app.route('/timer/<string:status>')
def mytimer(status, nsec=10):
    global t, job_timer
    if status=='on' and not t:
        schedule.every(nsec).seconds.do(run_job, str(uuid.uuid4()))
        t = Process(target=run_schedule)
        t.start()
        return "timer on with interval:{}sec\n".format(nsec)
    elif status=='off' and t:
        if t:
            t.terminate()
            t = None
            schedule.clear()
        return "timer off\n"
    return "timer status not changed\n"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

您可以通过以下方式对此进行测试:

$ curl http://127.0.0.1:5000/timer/on
timer on with interval:10sec
$ curl http://127.0.0.1:5000/timer/on
timer status not changed
$ curl http://127.0.0.1:5000/timer/off
timer off
$ curl http://127.0.0.1:5000/timer/off
timer status not changed

每隔10秒钟计时器就会向控制台发出一个计时器消息:

127.0.0.1 - - [18/Sep/2018 21:20:14] "GET /timer/on HTTP/1.1" 200 -
timer job id=b64ed165-911f-4b47-beed-0d023ead0a33
timer: 10.0117sec
timer job id=b64ed165-911f-4b47-beed-0d023ead0a33
timer: 10.0102sec

答案 6 :(得分:2)

我已经尝试过使用flask而不是简单的apscheduler来安装

pip3安装flask_apscheduler

下面是我的代码示例:

from flask import Flask
from flask_apscheduler import APScheduler

app = Flask(__name__)
scheduler = APScheduler()

def scheduleTask():
    print("This test runs every 3 seconds")

if __name__ == '__main__':
    scheduler.add_job(id = 'Scheduled Task', func=scheduleTask, trigger="interval", seconds=3)
    scheduler.start()
    app.run(host="0.0.0.0")

答案 7 :(得分:1)

您可能希望使用某些队列机制,例如RQ scheduler之类的调度程序或像Celery一样更重的东西(很可能是一种过度杀伤)。

答案 8 :(得分:0)

对于一个简单的解决方案,您可以添加一条路线,例如

@app.route("/cron/do_the_thing", methods=['POST'])
def do_the_thing():
    logging.info("Did the thing")
    return "OK", 200

然后add a unix cron job定期发布到此端点。例如,每分钟运行一次,在终端类型crontab -e中添加以下行:

* * * * * /opt/local/bin/curl -X POST https://YOUR_APP/cron/do_the_thing

(请注意,curl的路径必须是完整的,因为在作业运行时它将没有您的PATH。您可以通过which curl找到系统上curl的完整路径)

我之所以这样,是因为它易于手动测试作业,它没有额外的依赖关系,并且因为没有什么特别的事情,所以易于理解。

安全性

如果您想用密码保护您的cron作业,可以pip install Flask-BasicAuth,然后将凭据添加到您的应用程序配置中:

app = Flask(__name__)
app.config['BASIC_AUTH_REALM'] = 'realm'
app.config['BASIC_AUTH_USERNAME'] = 'falken'
app.config['BASIC_AUTH_PASSWORD'] = 'joshua'

要用密码保护作业端点:

from flask_basicauth import BasicAuth
basic_auth = BasicAuth(app)

@app.route("/cron/do_the_thing", methods=['POST'])
@basic_auth.required
def do_the_thing():
    logging.info("Did the thing a bit more securely")
    return "OK", 200

然后从您的cron作业中调用它:

* * * * * /opt/local/bin/curl -X POST https://falken:joshua@YOUR_APP/cron/do_the_thing

答案 9 :(得分:0)

你可以试试simple-scheduler

pip install simple-scheduler

您不仅可以安排(并且不会错过)execution_time > period_of_scheduling 的作业,还可以在发生故障时重新尝试执行任务。

from time import sleep, ctime, time
from simple_scheduler.recurring import recurring_scheduler

def wait_t_secs(t):
    began_at = ctime(time())
    sleep(t)
    print(f"I waited {t} seconds. [From: {began_at} to {ctime(time())}]")
# the above wait_t_secs function would be called twice,
# so to differentiate between then use "job_name"

recurring_scheduler.add_job(target=wait_t_secs,
                            kwargs={"t":7}, # period < execution time
                            period_in_seconds=5,
                            job_name="seven",
                            number_of_reattempts=3,
                            reattempt_duration_in_seconds=1)
recurring_scheduler.add_job(target=wait_t_secs,
                            kwargs={"t":3}, # period > execution time
                            period_in_seconds=5,
                            job_name="three",
                            number_of_reattempts=3,
                            reattempt_duration_in_seconds=1)

recurring_scheduler.verbose = True # (default)

recurring_scheduler.job_summary()
recurring_scheduler.run()
recurring_scheduler.job_summary()

答案 10 :(得分:-1)

您可以使用 flask-crontab 模块,这很简单。

第一步:pip install flask-crontab

第 2 步:

from flask import Flask
from flask_crontab import Crontab

app = Flask(__name__)
crontab = Crontab(app)

第 3 步:

@crontab.job(minute="0", hour="6", day="*", month="*", day_of_week="*")
def my_scheduled_job():
    do_something()

第 4 步:在 cmd 上,点击

flask crontab add

完成。现在只需运行您的 Flask 应用程序,您就可以检查您的函数是否会在每天 6:00 调用。

您可以参考Here(官方文档)。