uwsgi部署flask,flask_apscheduler任務遇到各種問題解決


背景:最近在做的全域事件項目,快要靠近尾聲了,需要用到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對象不會出現問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM