背景:最近在做的全域事件项目,快要靠近尾声了,需要用到uwsgi部署至生产环境,由于之前是debug模式,运行项目也是通过命令 python manager.py runserver (manage是通过flask_script创建的脚本管理,用于类似django的数据库初始化、迁移和管理app等操作)。现项目由uwsgi管理,由于uwsgi一些特性造成项目运行中出现的一系列问题,顺便记录下解决方案。

uwsgi.ini

 1 [uwsgi]
2 # 项目文件夹
3 chdir = xxx/xxx/xxx
4 # wsgi文件路经
5 wsgi-file = xxx/xxx/xxx/manage.py
6 # 回调的app对象
7 callback = manager
8 # 虚拟环境路经
9 home = /home/xxx/.virtualenvs/xxx
10 # 主进程
11 master = true
12 # 最大输了的工作进程
13 processes = 2
14 # 项目中使用的IP:端口
15 http = xxx.xxx.xxx.xxx:5000
16 # 退出的时候是否清理环境
17 vacuum = true
18 # uwsgi日志文件路经
19 daemonize = /home/xxx/xxx/xxx/uwsgi.log
20 # 进程pid文件
21 pidfile = /home/xxx/xxx/xxx/uwsgi.pid

一、uwsgi通过callback回调app,manager虽管理app,但并不能提供uwsgi所用到的回调的app,直接如上配置callback=manager,接口请求在uwsgi.log中会看到__callback__错误,因为数据库迁移后manager没什么用,因此将manager换成原app,如下:

manager.py

1 from xxx import create_app
2
3 # 创建flask应用对象
4 app = create_app("product")
5
6
7 if __name__ == '__main__':
8
9 app.run()

uwsgi.ini修改callback

1 # 回调的app对象
2 callback = app

二、flask_apscheduler定时任务不启动

uwsgi启动后在没有请求的时候,部分进程会被挂起,需在uwsgi.ini中增加如下配置:

1 # flask_apscheduler配置
2 enable-threads = true
3 preload = true
4 lazy-apps = true

三、uwsgi启动后,定时任务启动两次,重复启动

原因uwsgi中开启了两个进程,进程独享一份资源,因此两个进程都启动了各自的scheduler,网上找了许久解决方案后,最终确定用文件锁的方式解决

create_app函数中

 1 from xxx.tasks import scheduler
2 import os
3 import atexitcc
4 import fcntl
5
6 def create_app(config_name):
7 app = Flask(__name__, template_folder="static/")
8 。。。
9
10 # 使用app初始化任务
11 # 使用文件锁,解决flask_apscheduler定时任务重复启动问题
12 f = open(os.path.join(BASE_DIR, "xxx/xxx/scheduler.lock"), "wb")
13 try:
14 fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
15 scheduler.init_app(app)
16 scheduler.start()
17 except:
18 pass
19
20 def unlock():
21 fcntl.flock(f, fcntl.LOCK_UN)
22 f.close()
23
24 # 注册退出事件,如果flask项目退出,则解除scheduler.lock文件锁并关闭文件
25 atexit.register(unlock)

四、uwsgi启动项目后,config中配置的定时任务正常运行且不会重复启动,uwsgi.log中也可以看到scheduler正常启动;但通过api启动,使用scheduler.add_job()方式启动的任务,从uwsgi.log中发现是等待scheduler start状态,由此发现还是创建了两个scheduler对象。看了许久代码后发现了问题

因为项目中需要运行的任务较多,任务函数也都是需要区分开写在不同py文件中的,因此为了方便管理,我在项目中创建了tasks文件夹(python包),在tasks中的__init__.py文件中定义了scheduler对象,tasks中的各任务文件引用此scheduler并使用

tasks.__init__.py

 1 from flask_apscheduler import APScheduler
2 from apscheduler.schedulers.background import BackgroundScheduler
3 from multiprocessing import Queue
4
5 # APScheduler任务对象
6 scheduler = APScheduler(BackgroundScheduler(timezone="Asia/Shanghai"))
7
8 # 任务流
9 event_info_q = Queue()
10
11 # 处理的任务中间件列表
12 middleware_li = []

因此在uwsgi开启多进程情况下,scheduler还是因多进程创建了多次,加上文件锁的原因,仅一个scheduler被启动,于是改动如下:

tasks.__init__.py

1 # APScheduler任务对象
2 scheduler = None
3
4 # 任务流
5 event_info_q = Queue()
6
7 # 处理的任务中间件列表
8 middleware_li = []

create_app函数

 1 from flask_apscheduler import APScheduler
2 from apscheduler.schedulers.background import BaskgroundScheduler
3 from xxx import tasks
4 import os
5 import atexit
6 import fcntl
7
8 def create_app(config_name):
9 app = Flask(__name__, template_folder="static/")
10 。。。
11
12 # 使用app初始化任务
13 # 使用文件锁,解决flask_apscheduler定时任务重复启动问题
14 f = open(os.path.join(BASE_DIR, "xxx/xxx/scheduler.lock"), "wb")
15 try:
16 fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
17 tasks.scheduler = APScheduler(BaskgroundScheduler(timezone="Asia/Shanghai"))
18 tasks.scheduler.init_app(app)
19 tasks.scheduler.start()
20 except:
21 pass
22
23 def unlock():
24 fcntl.flock(f, fcntl.LOCK_UN)
25 f.close()
26
27 # 注册退出事件,如果flask项目退出,则解除scheduler.lock文件锁并关闭文件
28 atexit.register(unlock)

因为项目启动后首先调用的是create_app,create_app中将tasks.__init__.py中的scheduler重置为了APScheduler对象,并初始化app和启动,因此tasks文件夹内的各任务文件引用scheduler对象不会出现问题。

最新文章

  1. 解决windows 2003 无法安装vss2005的问题
  2. jquery ui dialog去掉右上角的叉号
  3. listview java.lang.ArrayIndexOutOfBoundsException:
  4. 2015年iOS测试现状
  5. mysql Access denied for user \'root\'@\'localhost\'”解决办法总结,下面我们对常见的出现的一些错误代码进行分析并给出解决办法,有需要的朋友可参考一下。
  6. 第九章 jQuery验证插件简介
  7. HDU 5007 Post Robot
  8. C#实现动态网站伪静态,使seo更友好
  9. JSTL语法及参数
  10. 六度分离--hdu1869
  11. Ceph对象存储网关中的索引工作原理<转>
  12. JavaScript之通用addLoadEvent代码源码
  13. 通过代码配置 Log4net来实现日志记录
  14. poj 1696 极角排序求最长逆时针螺旋线
  15. BZOJ_3048_[Usaco2013 Jan]Cow Lineup _双指针
  16. Docke--Dockerfile 构建LNMP环境
  17. FFmpeg 结构体学习(五): AVCodec 分析
  18. Java z 404
  19. [转]Rapidly detecting large flows, sFlow vs. NetFlow/IPFIX
  20. Zookeeper源码编译为Eclipse工程(win7下Ant编译)

热门文章

  1. NuxtJS踩坑日记,一步一步爬出我自己挖的坑。
  2. 方法的调用-JDK的JShell简单使用
  3. 在腾讯云上创建一个玩具docker-mysql数据服务
  4. python开发云主机类型管理脚本
  5. JAVA虚拟机12--Class文件结构-属性表
  6. Google_MapReduce中文版
  7. 使用Navicat操作MySQL数据库
  8. P22_条件渲染
  9. eigen的简单用法汇总
  10. odoo 给列表视图添加按钮实现数据文件导入