teprunner測試平台定時任務這次終於穩了
teprunner測試平台已經有一個多月沒有更新了,主要原因是定時任務不夠穩定,經過反覆試錯,找到了解決辦法,這次終於穩定了。
本文開發內容
作為測試平台而言,定時任務算是必備要素了,只有跑起來的自動化,才能算是真正的自動化。本文將給測試計劃添加定時任務功能,具體如下:
- 前端添加測試計劃的定時任務開關
- 採用crontab表達式設置計劃時間
- 後端集成django-apschedule,在資料庫中記錄任務明細和執行詳情。
- 定時清理執行記錄。
前端效果圖:
前端開發內容
編輯src/views/teprunner/plan/PlanEditor.vue文件:
運行環境用el-select
實現了下拉框,用el-switch
實現了開關按鈕。
el-pophover
實現了幫助描述,可以參考編寫crontab表達式。
在data中添加了表單項taskRunEnv、taskStatus、taskCrontab,必填規則,以及其他變數。
頁面創建時讀取localStorage中的計劃資訊。
並獲取運行環境下拉框選項。
開關按鈕的文字是根taskStatus進行設置的。
在保存時,給請求添加上新的這3個參數。
後端開發內容
第一步是安裝django-apscheduler,要麼直接安裝:
pip install django-apscheduler
要麼更新項目程式碼後通過requirements.txt安裝:
pip install -r requirements.txt
然後編輯teprunnerbackend/settings.py文件:
在INSTALLED_APPS中添加django_apscheduler。
接著遷移資料庫,創建兩張任務表,一張任務明細表,一張任務執行情況表:
python manage.py migrate
編輯teprunner/models.py文件:
給Plan模型添加3個欄位。
編輯teprunner/serializers.py文件:
同樣的,給PlanSerializer添加3個欄位。
新建teprunner/views/task.py文件:
創建BackgroundScheduler的對象實例,Background指的是在後台運行。並添加DjangoJobStore,把任務通過Django保存到資料庫中。
添加一個定時刪除執行記錄的任務,max_age是最大保存時間,這裡設置為7天。scheduler.add_job()用來添加定時任務,trigger是觸發器,也就是計劃時間,這裡設置為每周一0點。id是任務的標識符。max_instances指同時最多只有一個實例。replace_existing設置為True,每次都更新已存在的任務,防止重啟服務導致scheduler.add_job()報錯。
啟動任務。
編輯teprunner/views/run.py文件:
為了手動執行測試計劃和定時任務執行測試計劃共用,這裡把執行程式碼抽取了部分作為run_plan_engine()函數。
編輯teprunner/views/plan.py文件:
重寫create方法,先根據測試計劃的名字判斷是否已存在,如果存在就直接返回500。接著判斷開關如果開啟,那麼就通過scheduler.add_job()添加任務。跟剛才添加任務的有點區別是,通過args參數指定了func函數的參數。最後把任務添加日誌寫到響應中返回。
重寫update方法,先判斷測試計劃是否已經存在,判斷規則是根據名字去查找已存在記錄,如果找到同名計劃,且id不是自己,那麼就認為已存在同名計劃,直接返回500。
然後判斷如果開關打開,就新增任務;如果開關關閉,就刪除任務,刪除任務使用scheduler.remove_job()。
最後重寫destroy方法,在刪除測試計劃時,一併刪除定時任務。
猴子修補程式解決pymysql連接問題
為什麼定時任務會不穩定?因為我用的pymysql庫,它不會進行資料庫連接斷開後重試。Django和MySQL建立建立後,何時斷開連接通過CONNECT_MAX_AGE來設置,默認是0,表示使用完馬上斷開連接。Django只會對Web請求採取這個策略,使用signals.request_started.connect(close_old_connections)和signals.request_finished.connect(close_old_connections)來關閉舊連接。但定時任務不是Web請求,而是直接連接資料庫,Django並不會去主動斷開這個連接。而MySQL默認8小時會把連接斷掉,於是當Django拿著已經被MySQL斷開的連接對象去請求MySQL,就報錯了。
當我在本地安裝了MySQL後,重啟MySQL就能復現這個問題。
解決辦法一是把舊連接復活,進行斷線重連,但是會導致連接佔用可能越來越多,耗費資源。解決辦法二是像Django處理Web請求一樣,每次用完就斷開,下次使用再重新連接,佔用資源少。
猴子修補程式是指不修改第三方庫的基礎上,對庫的功能進行擴展。我給django-apscheduler寫了個猴子修補程式,實現第二個解決辦法,用完就斷開連接:
並且通過issue方式,告訴了它的作者:
這開啟了我在GitHub上英文交流技術的大門。
比如我又給loguru提了個bug,此時已經和loguru的作者英文交流了5個回合。
小結
本文給測試計劃添加了定時任務功能,為teprunner測試平台補上了一塊重要拼圖。從此它不但能批量執行用例了,還能按照計劃時間,定時執行,實現了真正的自動化。