teprunner測試平台定時任務這次終於穩了

teprunner測試平台已經有一個多月沒有更新了,主要原因是定時任務不夠穩定,經過反覆試錯,找到了解決辦法,這次終於穩定了。

本文開發內容

作為測試平台而言,定時任務算是必備要素了,只有跑起來的自動化,才能算是真正的自動化。本文將給測試計劃添加定時任務功能,具體如下:

  • 前端添加測試計劃的定時任務開關
  • 採用crontab表達式設置計劃時間
  • 後端集成django-apschedule,在資料庫中記錄任務明細和執行詳情。
  • 定時清理執行記錄。

前端效果圖:

image-20210528222640069

前端開發內容

編輯src/views/teprunner/plan/PlanEditor.vue文件:

image-20210528222823663

運行環境用el-select實現了下拉框,用el-switch實現了開關按鈕。

image-20210528223000259

el-pophover實現了幫助描述,可以參考編寫crontab表達式。

image-20210528223141339

在data中添加了表單項taskRunEnv、taskStatus、taskCrontab,必填規則,以及其他變數。

image-20210528223326133

頁面創建時讀取localStorage中的計劃資訊。

image-20210528223407162

並獲取運行環境下拉框選項。

image-20210528223437261

開關按鈕的文字是根taskStatus進行設置的。

image-20210528223522132

在保存時,給請求添加上新的這3個參數。

後端開發內容

第一步是安裝django-apscheduler,要麼直接安裝:

pip install django-apscheduler

要麼更新項目程式碼後通過requirements.txt安裝:

pip install -r requirements.txt

然後編輯teprunnerbackend/settings.py文件:

image-20210528223904507

在INSTALLED_APPS中添加django_apscheduler。

接著遷移資料庫,創建兩張任務表,一張任務明細表,一張任務執行情況表

python manage.py migrate

image-20210528224044201

編輯teprunner/models.py文件:

image-20210528224148248

給Plan模型添加3個欄位。

編輯teprunner/serializers.py文件:

image-20210528224243250

同樣的,給PlanSerializer添加3個欄位。

新建teprunner/views/task.py文件:

image-20210528224352704

創建BackgroundScheduler的對象實例,Background指的是在後台運行。並添加DjangoJobStore,把任務通過Django保存到資料庫中。

image-20210528224622874

添加一個定時刪除執行記錄的任務,max_age是最大保存時間,這裡設置為7天。scheduler.add_job()用來添加定時任務,trigger是觸發器,也就是計劃時間,這裡設置為每周一0點。id是任務的標識符。max_instances指同時最多只有一個實例。replace_existing設置為True,每次都更新已存在的任務,防止重啟服務導致scheduler.add_job()報錯。

image-20210528225020524

啟動任務。

編輯teprunner/views/run.py文件:

image-20210528225152787

為了手動執行測試計劃和定時任務執行測試計劃共用,這裡把執行程式碼抽取了部分作為run_plan_engine()函數。

編輯teprunner/views/plan.py文件:

image-20210528225455141

重寫create方法,先根據測試計劃的名字判斷是否已存在,如果存在就直接返回500。接著判斷開關如果開啟,那麼就通過scheduler.add_job()添加任務。跟剛才添加任務的有點區別是,通過args參數指定了func函數的參數。最後把任務添加日誌寫到響應中返回。

image-20210528225724696

重寫update方法,先判斷測試計劃是否已經存在,判斷規則是根據名字去查找已存在記錄,如果找到同名計劃,且id不是自己,那麼就認為已存在同名計劃,直接返回500。

image-20210528225911350

然後判斷如果開關打開,就新增任務;如果開關關閉,就刪除任務,刪除任務使用scheduler.remove_job()。

image-20210528230002678

最後重寫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寫了個猴子修補程式,實現第二個解決辦法,用完就斷開連接:

image-20210528231438135

並且通過issue方式,告訴了它的作者:

image-20210528231757896

這開啟了我在GitHub上英文交流技術的大門。

比如我又給loguru提了個bug,此時已經和loguru的作者英文交流了5個回合。

小結

本文給測試計劃添加了定時任務功能,為teprunner測試平台補上了一塊重要拼圖。從此它不但能批量執行用例了,還能按照計劃時間,定時執行,實現了真正的自動化。

Tags: