簡單提一下這個問題,先講思路,后面再進行深入的探索和決議和發散
事情發生在筆者開發某個typescript服務端專案的程序中,筆者需要將一個基于typeorm的讀寫資料庫操作進行異步處理,也就是不阻塞當前執行緒,
大體是這樣的一個行文:
// 用于typeorm的models檔案中
class Person {
@Column({ nullable: true })
code: string | null = null;
async initCode() {
if (!this.code) return;
this.code = randomAlphabet(); // 隨機生成的code
}
}
// 讀寫資料庫檔案中, eg: repos/person.ts
async function generateCode(person: Person): Promise<Person> {
try {
person.initCode();
} catch (e) {
// error catcher
}
}
// 處理邏輯的controllers中,eg: controllers/personController.ts
async function generateCodeForPerson(ctx, next): Promise<void> {
const person = await getPerson(ctx.params.id);
void generateCode(person); // 這里不做await,選擇異步處理
ctx.code = 200;
}
那么好,由于該專案比較重要,所以筆者所在專案組使用jest進行e2e測驗,以確保api可用,同時會部署CI,用于在pull request程序中進行代碼自測,
其中測驗generateCode大致是這么一個走法:
describe('testGenerateCode', async () => {
let runInBackgroundMock: jest.SpyInstance<
void,
[callback: () => Promise<unknown>]
>; // 這個是jest用于劫持運行函式中的函式后,將函式中的異步改同步的操作
beforeAll(async () => {
// 此處,將測驗函式中所運行的utils.runInBackground方法進行mock,取消其異步性,將在未來筆記中深入講解
runInBackgroundMock = jest
.spyOn(utils, 'runInBackground')
.mockImplementation();
initDB(); // 初始化CI程序中連接測驗DB的Client,占用DB連接資源
})
/**
* 此處不止一個describe
*/
describe('should successful', async () => {
await testGenerateCodeForPerson(); // 其中呼叫了generateCodeForPerson,但是比較深,所以當時沒發現
})
afterAll(async () => {
closeDB(); // 關掉DBClient,釋放DB連接資源
})
});
細心的讀者應該能夠但從中發現問題了:萬一沒執行完generateCode的內容,就closeDB了,那不就出問題了?
沒錯!筆者遇到這個問題了,但第一時間沒有意識到問題來自筆者的代碼,下面是CI的報錯:

此處插入題外話,筆者發現CI執行每個e2e的測驗檔案的次序是固定的,走到generateCode的下一個e2e測驗任務就馬上會遇到該問題,以至于筆者一直以為是任務A出了問題,但本地單獨jest該任務永遠都是Pass的,致使筆者一度有些...
但是經過前輩的指導,其中一個就是讓筆者在本地使用CI所使用的命令,對所有e2e測驗檔案進行測驗,而不是對單個e2e測驗檔案進行測驗,同時,前輩讓筆者留意是否與DB之間的連接關閉之后仍然有著讀寫DB的操作,
也就是說:
# 用這個
yarn jest tests/e2e
# 而不是用這個
yarn jest tests/e2e/generate_code_for_person.ts
得益于本地運行命令,筆者發現測驗檔案的執行順序并不是固定的,自然而然地發現每一個跟在generateCode的后e2e測驗任務就會QueryFailedError,于是進行了注釋debug方法,也就是每個describe都注釋一下,最后鎖定了問題出在generateCode函式中,
由此,筆者悻悻地將代碼給改了,給controllers/personController.ts中加了一個utils.runInBackground,
也就是:
// 處理邏輯的controllers中,eg: controllers/personController.ts
async function generateCodeForPerson(ctx, next): Promise<void> {
const person = await getPerson(ctx.params.id);
utils.runInBackGround(async () => {
await generateCode(person); // 這里做不做await好像都沒所謂了,
});
ctx.code = 200;
}
于是乎就這么改了,CI就過了,
所以后續會繼續記錄在進行和使用jest、postgres sql、typeorm、資料庫表設計程序中的的所見所聞,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/552502.html
標籤:其他
上一篇:在我有限的軟體測驗經歷里,一段專職的自動化測驗經驗總結
下一篇:返回列表
