Flask后端实践 连载九 Flask-APScheduler定时任务与坑点解决方法

Flask-APScheduler定时任务与坑点解决方法

tips:

项目背景

在项目中会遇到各种定时任务,比如定时清理文件,定时计算报表等。

APScheduler

APScheduler的全称是Advanced Python Scheduler。它是一个轻量级的 Python 定时任务调度框架。APScheduler 支持三种调度任务:固定时间间隔,固定时间点(日期),Linux 下的 Crontab 命令。同时,它还支持异步执行、后台执行调度任务。官方文档

一、简单使用

  1. 安装pip install apscheduler
  2. 示例,每5秒输出时间
    from apscheduler.schedulers.blocking import BlockingScheduler
    from datetime import datetime
    
    def timed_task():
        print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    
    if __name__ == '__main__':
        # 创建当前线程执行的schedulers
        scheduler = BlockingScheduler()
        # 添加调度任务(timed_task),触发器选择interval(间隔性),间隔时长为5秒
        scheduler.add_job(timed_task, 'interval', seconds=5)
        # 启动调度任务
        scheduler.start()
    

二、调度器(scheduler)

  • BlockingScheduler: 调度器在当前进程的主线程中运行,会阻塞当前线程。
  • BackgroundScheduler: 调度器在后台线程中运行,不会阻塞当前线程。
  • AsyncIOScheduler: 结合asyncio模块一起使用。
  • GeventScheduler: 程序中使用gevent作为IO模型和GeventExecutor配合使用。
  • TornadoScheduler: 程序中使用Tornado的IO模型,用 ioloop.add_timeout 完成定时唤醒。
  • TwistedScheduler: 配合TwistedExecutor,用reactor.callLater完成定时唤醒。
  • QtScheduler: 应用是一个Qt应用,需使用QTimer完成定时唤醒。

三、触发器(trigger)

  • date是最基本的一种调度,作业任务只会执行一次。参数详见

  • interval触发器,固定时间间隔触发。参数详见

  • cron 触发器,在特定时间周期性地触发,和Linux crontab格式兼容。它是功能最强大的触发器。参数详见

四、作业存储(job store)

  • 添加任务,有两种添加方法,一种add_job(), 另一种是scheduled_job()修饰器来修饰函数。

    from datetime import datetime
    from apscheduler.schedulers.blocking import BlockingScheduler
    scheduler = BlockingScheduler()
    
    # 第一种
    @scheduler.scheduled_job(job_func, 'interval', seconds=10)
    def timed_task():
        print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    # 第二种
    scheduler.add_job(timed_task, 'interval', seconds=5)
    
    scheduler.start()
    
  • 删除任务,两种方法:remove_job()job.remove()remove_job()是根据任务的id来移除,所以要在任务创建的时候指定一个 id。job.remove()则是对任务执行remove方法。

    scheduler.add_job(job_func, 'interval', seconds=20, id='one')
    scheduler.remove_job(one)
    
    task = add_job(task_func, 'interval', seconds=2, id='job_one')
    task.remvoe()
    
  • 获取任务列表,通过scheduler.get_jobs()方法能够获取当前调度器中的所有任务的列表

    tasks = scheduler.get_jobs()
    
  • 关闭任务,使用scheduler.shutdown()默认情况下调度器会等待所有正在运行的作业完成后,关闭所有的调度器和作业存储。

    scheduler.shutdown()
    scheduler.shutdown(wait=false)
    

五、执行器(executor)

执行器是执行调度任务的模块。最常用的 executor 有两种:ProcessPoolExecutorThreadPoolExecutor

Flask与APScheduler结合

  1. 安装pip install flask_apscheduler
  2. 将apscheduler注册到Flask App
    • 编写 core.py
      from flask_apscheduler import APScheduler
      scheduler = APScheduler()
      
    • 编写factory.py
      from core import scheduler
      def create_app():
          app = Flask(__name__)
          # 配置任务,不然无法启动任务
          app.config.update(
              {"SCHEDULER_API_ENABLED": True,
               "JOBS": [{"id": "my_job", # 任务ID
                          "func": "task:my_job",#任务位置
                          "trigger": "interval", #触发器
                          "seconds": 5 # 时间间隔
                          } 
                      ]}
              )
          scheduler.init_app(app)
          scheduler.start()
          return app
      
  3. 编写定时任务task.py
    def my_job():
        print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
    
  4. 创建app.py
    from factory import create_app
    
    app = create_app()
    if __name__ == "__main__":
        app.run()
    
  5. 测试 执行python app.py,控制台输出如下:
    Running job "my_job (trigger: interval[0:00:05], next run at: 2019-04-27 17:26:31 CST)" (scheduled at 2019-04-27 17:26:31.477195+08:00)
    Job "my_job (trigger: interval[0:00:05], next run at: 2019-04-27 17:26:36 CST)" executed successfully
    2019-04-27 17:26:31
    Running job "my_job (trigger: interval[0:00:05], next run at: 2019-04-27 17:26:33 CST)" (scheduled at 2019-04-27 17:26:33.410837+08:00)
    Job "my_job (trigger: interval[0:00:05], next run at: 2019-04-27 17:26:38 CST)" executed successfully
    2019-04-27 17:26:33
    

踩坑点

  1. 多进程部署,定时任务重复启动解决方法

    • 解决思路:在启动任务时,设置文件锁,当能获取到文件锁时,不在启动任务
    • 代码
      #factory.py
      def create_app():
          app =Flask(__name__)
          # 启动定时任务
          scheduler_init(app)
          return app
      
      def scheduler_init(app):
          """
          保证系统只启动一次定时任务
          :param app:
          :return:
          """
          if platform.system() != 'Windows':
              fcntl = __import__("fcntl")
              f = open('scheduler.lock', 'wb')
              try:
                  fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
                  scheduler.init_app(app)
                  scheduler.start()
                  app.logger.debug('Scheduler Started,---------------')
              except:
                  pass
      
              def unlock():
                  fcntl.flock(f, fcntl.LOCK_UN)
                  f.close()
      
              atexit.register(unlock)
          else:
              msvcrt = __import__('msvcrt')
              f = open('scheduler.lock', 'wb')
              try:
                  msvcrt.locking(f.fileno(), msvcrt.LK_NBLCK, 1)
                  scheduler.init_app(app)
                  scheduler.start()
                  app.logger.debug('Scheduler Started,----------------')
              except:
                  pass
      
              def _unlock_file():
                  try:
                      f.seek(0)
                      msvcrt.locking(f.fileno(), msvcrt.LK_UNLCK, 1)
                  except:
                      pass
      
              atexit.register(_unlock_file)
      
  2. Gunicorn使用gevent模式无效解决方法

    • 解决思路:将gunicorn启动模式换为eventlet
    • 配置文件gun.conf
      # 并行工作进程数
      workers = 4
      # 指定每个工作者的线程数
      threads = 4
      # 监听内网端口80
      bind = '0.0.0.0:80'
      # 工作模式协程
      worker_class = 'eventlet' 
      # 设置最大并发量
      worker_connections = 2000
      # 设置进程文件目录
      pidfile = 'gunicorn.pid'
      # 设置访问日志和错误信息日志路径
      accesslog = './logs/gunicorn_acess.log'
      errorlog = './logs/gunicorn_error.log'
      # 设置日志记录水平
      loglevel = 'info'
      # 代码发生变化是否自动重启
      reload=True
      
  3. 使用Flask数据库解决方法

    • 解决思路:数据注册时指定一下app,并在定时任务中使用数据库绑定的app栈

    • factory.py配置

      def create_app():
          app =Flask(__name__)
          # 数据库注册
          db.app = app
          db.init_app(app)
          app.config.update(
              {"SCHEDULER_API_ENABLED": True,
               "JOBS": [{"id": "db_query", # 任务ID
                          "func": "task:db_query",#任务位置
                          "trigger": "interval", #触发器
                          "seconds": 5 # 时间间隔
                          } 
                      ]}
              )
          scheduler_init(app)
          return app
      
    • task.py中使用数据库

      from app.utils.core import db
      
      def db_query():
          """
          定时任务使用数据库
          """
          with db.app.app_context():
               data =db.session.query(user).first()
               print(data)
      
      

总结

  • 简单的使用了Flask-APScheduler
  • 实际生产中遇到的问题解决方法
  • 下一章将介绍Flask实现图形验证码及验证
  • 14
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
### 回答1: 可以使用Flask-APScheduler在MongoDB中实现定时任务,只需要在Flask应用中定义一个定时任务,并将其配置为在MongoDB中运行。具体代码如下:from flask_apscheduler import APSchedulerscheduler = APScheduler()# Configure the scheduler to use MongoDB as its job store scheduler.add_jobstore('mongodb', host='localhost', database='your_database_name')@scheduler.task('interval', id='do_job_1', seconds=30) def job_1(): print("Job 1 executed")@scheduler.task('cron', id='do_job_2', day_of_week='mon-sun', hour='12', minute='30') def job_2(): print("Job 2 executed")# Start the scheduler scheduler.start() ### 回答2: 要使用Flask-APScheduler实现数据库MongoDB定时任务,首先需要安装Flask-APScheduler和pymongo库。在Flask应用程序中,可以使用以下代码实现: 1. 首先,在app.py文件中导入所需的模块和库: ```python from flask import Flask from flask_apscheduler import APScheduler from pymongo import MongoClient ``` 2. 创建Flask应用程序实例: ```python app = Flask(__name__) ``` 3. 配置MongoDB连接并创建MongoDB客户端: ```python app.config['MONGO_URI'] = 'mongodb://localhost:27017/db_name' mongo_client = MongoClient(app.config['MONGO_URI']) ``` 请注意,`db_name`应替换为你的实际数据库名称,`localhost:27017`应替换为你的MongoDB服务器地址和端口。 4. 初始化APScheduler实例并配置任务存储: ```python scheduler = APScheduler() scheduler.init_app(app) scheduler.start() ``` 5. 创建一个定时任务函数,该函数将执行需要定时执行的操作。这里以向MongoDB数据库中插入一条记录为例: ```python def insert_data(): db = mongo_client.db_name collection = db.collection_name data = {'name': 'John', 'age': 30} collection.insert_one(data) ``` 请注意,`db_name`和`collection_name`应替换为你的实际数据库和集合名称。 6. 创建一个定时任务,并将其添加到APScheduler中: ```python scheduler.add_job(func=insert_data, trigger='interval', seconds=60) ``` 这将每隔60秒执行一次`insert_data`函数。 7. 最后,在Flask应用程序的入口处,启动Flask应用程序: ```python if __name__ == '__main__': app.run() ``` 以上代码片段演示了如何使用Flask-APScheduler和pymongo库实现数据库MongoDB定时任务的基本步骤。根据实际需求,你可以根据需要调整设置和任务函数。 ### 回答3: 要使用Flask-APScheduler实现MongoDB数据库的定时任务,需要先安装FlaskFlask-APScheduler库,并且确保MongoDB数据库已经正确安装和配置。 首先,在Flask应用中导入所需要的库和模块: ```python from flask import Flask from flask_apscheduler import APScheduler from pymongo import MongoClient ``` 然后,创建Flask应用和APScheduler实例并配置MongoDB数据库的连接: ```python app = Flask(__name__) scheduler = APScheduler() scheduler.init_app(app) # 配置MongoDB数据库连接 client = MongoClient('mongodb://localhost:27017/') # 替换为实际的MongoDB连接地址 db = client['mydatabase'] # 替换为实际的数据库名称 ``` 接下来,创建一个定时任务函数,该函数在特定时间间隔内会被调度执行,并且可以在函数中访问MongoDB数据库: ```python @scheduler.task('interval', id='my_job', minutes=30) def my_task(): collection = db['mycollection'] # 替换为实际的集合名称 # 在此处添加需要执行的MongoDB操作,例如插入、更新、删除等 # 例如:collection.insert_one({"name": "example"}) ``` 最后,启动定时任务调度器和Flask应用: ```python @app.route('/') def index(): return 'Flask-APScheduler MongoDB Demo' if __name__ == '__main__': scheduler.start() app.run() ``` 启动应用后,定时任务会按照预定的时间间隔执行,并且可以在`my_task()`函数中进行MongoDB的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值