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測試平臺補上了一塊重要拼圖。從此它不但能批量執行用例了,還能按照計劃時間,定時執行,實現了真正的自動化。