1. 程式人生 > 其它 >uwsgi部署flask,flask_apscheduler任務遇到各種問題解決

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物件不會出現問題。