python(flask/gunicorn)+apscheduler定時郵件重發兩次的問題


工作中遇到一個需求,要在現有系統(airbnb家的開源平台superset)上添加一個定時郵件的功能。

定時郵件功能使用的是apscheduler這個庫,關於怎么用這里就不多贅述了反正網上都有。

主要記錄一個問題,使用過程中發現郵件有的時候會重發兩次,經過研究之后發現是runserver的時候,調度器實例被創建了兩次。

這個主要和系統使用的flask的一個reload機制有關(FLASK_USE_RELOAD = True),reload主要用於代碼的熱更新(簡單解釋就是,當你runserver啟動服務的時候,會先創建一個主進程,主進程再創建一個子進程。子進程是實際運作的系統,而主進程的主要作用在於監聽代碼的改變,當你python install重裝代碼時,主進程探測到代碼的改變,就會自動重啟子進程,達到代碼熱更新的效果)。

因此當你runserver時,會發現代碼被執行了兩遍。但在系統中調度器實例只應被執行一次,這時可以添加判斷條件:if os.environ.get('WERKZEUG_RUN_MAIN') == 'true' ,創建主進程時會發現此變量值為None,而創建子進程時此變量為true,僅當此變量為true時創建調度器實例,即可避免上述問題。

 

-------------------------------------

2018-01-17 更新:

后來系統換用gunicorn部署,發現這個問題又回來了,而且gunicorn設置多少個worker,啟動apscheduler的代碼就被執行了多少次。

解決方法:

(1)使用--preload啟動gunicorn(這樣會發現代碼在master啟動時執行了一次,而在所有worker啟動前總共也只執行了一次,這樣問題就和之前flask自帶的測試服務器類似了)

(2)gunicorn下會發現os.environ里找不到'WERKZEUG_RUN_MAIN'這個變量了,一個變通的想法是找到master啟動時不會觸發,而worker啟動時才會觸發的代碼段,手動用os.environ.setdefault('RUN_WORKER', 'true')來達到目的

 

參考文章:

http://simple-is-better.com/news/1039

https://stackoverflow.com/questions/25504149/why-does-running-the-flask-dev-server-run-itself-twice


免責聲明!

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



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