如果您已經在大型測試套件中使用過 Playwright 一段時間,那麼您可能已經使用過--shard選項將測試並行化到多台機器或 CI 執行器上。乍一看,這似乎是完美的解決方案。但隨著測試套件的成長,您開始注意到一個令人沮喪的問題:有些測試執行器在合理的時間內完成,而其他測試執行器可能需要更長的時間。最終,您只能等待最慢的執行器完成。

造成這種情況的主要原因在於 Playwright 的分片機制:它是靜態的。它會在測試開始前將測試檔案分割成均勻的區塊,並將每個區塊分配給特定的機器或 CI 執行器。例如,如果您在 4 個執行器上進行分片,它會將您的測試分成 4 個預定的群組。

# Runner 1 runs the first quarter of tests
npx playwright test --shard=1/4

# Runner 2 runs the second quarter
npx playwright test --shard=2/4

# ...and so on

如果所有測試耗時完全相同,這種方法會非常有效。但在現實世界中,這種情況永遠不會發生。有些測試簡短簡單,而有些測試則涉及複雜的使用者流程,耗時更長。這種靜態劃分會導致嚴重的不平衡:

  • 負荷分佈不均勻:一名跑步者可能通過了所有「簡單」的測試,並提前完成,無所事事。

  • 浪費資源:當一名跑步者閒著的時候,另一名跑步者卻在為一長串「艱難」的測試而苦苦掙扎。

  • 更長的執行時間:您的總測試執行時間由最慢的分片決定,而不是平均值。

現實世界的例子

為了讓這個問題更加具體,讓我們來看看真實的 GitLab CI 管道的螢幕截圖,其中 53 個測試套件分佈在 4 個執行器上。

GitLab CI 管道範例

如您所見,測試分佈遠非平衡:

  • 跑者 1(片段 1/4): 46 秒

  • 跑者 2(碎片 2/4): 1 分 45 秒

  • 跑者 3(片段 3/4): 41 秒

  • 跑者 4(碎片 4/4): 1 分 1 秒

我們測試套件的總執行時間由最慢的執行器決定,耗時1 分 45 秒。同時,執行器 3 僅用了41 秒就完成了!這意味著我們的一個 CI 執行器完全閒置了一分鐘多,等待其他執行器趕上來。這是一個靜態分片導致 CI/CD 資源浪費和反饋週期延長的例子。

解決方案:使用 Pawdist 進行動態測試分發

我想介紹一下Pawdist ,這是一款基於 Rust 的高效能動態測試分發器,由我開發,旨在解決此問題。 Pawdist 不使用預先分配測試,而是使用成熟的Manager-Worker架構:

  • 管理器:它會掃描您的所有測試並建立一個單獨的工作佇列。

  • 工作器:它們連接到管理器並請求測試。一旦工作器完成測試,它就會從佇列中請求下一個測試。

這樣,CI 執行器就不會閒著。快速完成短測試的執行器可以立即取得下一個可用測試,從而更快地清空佇列。這可以確保您的資源得到更有效率的利用,直到最後一個測試完成。

攤牌:Pawdist 與 Playwright Sharding

為了示範實際影響,我建立了一個包含 100 個測試的範例 Playwright 專案。我特意設計它來暴露靜態分片的弱點:

  • 測試 1-50:故意設得比較長,每次耗時 15-25 秒。

  • 測試 51-100:故意縮短,每次耗時 1-15 秒。

// A snippet from the test file to show the imbalance
import { test, expect } from '@playwright/test';

// ...

test('Distribution Test 4', async ({ page }) => {
  await page.waitForTimeout(25000); // 25 seconds (long test)
  expect(true).toBe(true);
});

// ...

test('Distribution Test 77', async ({ page }) => {
  await page.waitForTimeout(1000); // 1 second (short test)
  expect(true).toBe(true);
});

我使用三種不同的方法執行了這個測試套件,並將這些方法的總平行數保持在 4。

執行 1:基線(無分片)

首先,我在一台機器上用 4 個並行工作器執行了全部 100 個測試。這給了我們最佳場景下的時間。

圖片描述

整個測試套件在 6 分 3 秒內完成。

第二次執行:靜態分片的不平衡

接下來,我將測試分成兩個執行器(模擬兩台 CI 機器),每個執行器執行 2 個並行工作器。

圖片描述

由於 Playwright 按順序拆分測試,結果造成了嚴重的不平衡:

  • 碎片 1/2(測試 1-50):收到所有長測試,耗時8 分 36 秒

  • Shard 2/2(測試 51-100):完成了所有簡短的測試,僅用了3 分 32 秒就完成了。

由於最慢的分片,總執行時間膨脹至 8 分 36 秒。

執行 3:Pawdist 解決方案(動態分佈)

最後,我使用 Pawdist 和兩個工人,每個工人設定為 2 個並行執行者。

圖片描述

日誌清晰地展現了動態分配的魔力。工作器不再局限於一組預先定義的測試,而是從一個共享的佇列中拉取資料。當一個工作器完成一個測試(無論長短)後,它會立即從中央佇列請求下一個測試。這確保了即使一個工作器忙於一個長測試,另一個工作器也能同時完成幾個短測試,從而有效地即時平衡負載。

整個測試套件在6 分 5 秒內完成,幾乎與理想基線相匹配,並消除了靜態分片造成的巨大不平衡。

|方法|總執行時間|

|------------------------|--------------------------------|

| 基線(無分片)| 6 分 3 秒 |

| 劇作家 Sharding | 8 分 36 秒 |

| Pawdist | 6分5秒 |

基準測試結果不言而喻。 Pawdist 提供了分散式測試的可擴充性,而沒有靜態分片的效能損失。

準備好加速您的測試了嗎?

如果您希望優化 Playwright 測試執行時間並充分利用 CI 資源,請嘗試 Pawdist!

透過切換到動態分發模型,您可以實現:

  • 更快的整體執行:當最後一個測試完成時,您的套件就會完成,而不是最慢的碎片。

  • 最佳資源利用:不再有空閒的 CI 執行者等待其他人趕上。

  • 真正的動態負載平衡:按需分配測試以實現最高效率。

有關詳細的安裝和使用說明,您可以查看GitHub上該專案的綜合 README。


原文出處:https://dev.to/muhendiskedibey/is-playwrights-sharding-slowing-you-down-meet-pawdist-iap


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝10   💬6   ❤️11
448
🥈
我愛JS
📝1   💬6   ❤️4
93
🥉
AppleLily
📝1   💬4   ❤️1
46
#4
💬2  
6
#5
💬1  
5
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次