How CloudX cut CI test times by 69% with a simple swap

Replacing GitHub's setup-go action with a smarter caching strategy eliminated 86% of unnecessary test runs.

18 cards · 3m · tap to begin

From · · 3m

How CloudX cut CI test times by 69% with a simple swap

Replacing GitHub's setup-go action with a smarter caching strategy eliminated 86% of unnecessary test runs.

In brief

Replacing GitHub's setup-go action with a smarter caching strategy eliminated 86% of unnecessary test runs. Parallel CI jobs need separate cache keys to avoid racing and loading stale data that forces unnecessary retesting. Originally reported by CloudX | Ad Infrastructure for the Intelligence Era.

A drop-in replacement for setup-go

CloudX built a new GitHub Action that cut test job runtimes by 69%. They're open-sourcing it so other teams can get the same speedup.

The default action wastes effort

GitHub's official actions/setup-go makes parallel jobs interfere with each other. Backtesting shows 86% of the work it does is unnecessary.

“86% of the work the default action does is completely unnecessary.”

Fast CI enables fast shipping

Fast CI enables fast shipping

CloudX invests heavily in CI speed because reliable, quick tests let teams build fast without breaking things for customers.

The 90-second goal

When you push code to CloudX, the goal is a clear answer on whether it builds, passes tests, and meets linter rules within 90 seconds.

Algorithmic improvements matter most

CloudX already uses Warp Build for fast machines. As their test suite scaled, they realized actions/setup-go wasn't setting them up for success.

The cache key is incomplete

The default cache key only includes OS, architecture, Go version, and go.mod hash. Most code changes don't modify any of these.

Stale caches slow everything down

actions/cache only writes a fresh blob to the GitHub Actions cache service if the job succeeds and there was no exact match for that key initially. Once written

The first job run persists cache state. Until go.mod changes, every run loads that first value, which gets staler as you change code.

Parallel jobs race each other

Multiple parallel jobs running setup-go race to write different cache states. The winner's cache might not help the other jobs at all.

When lint wins, tests lose

If a lint job finishes first, it saves a cache without test results. Subsequent test jobs keep using that stale value and re-run tests unnecessarily.

Go's toolchain caches are smart

The Go toolchain saves module downloads, build artifacts, and test results. It only recomputes when inputs actually change.

Three caches work together

The module cache stores downloaded source code. The build cache stores package archives. The test cache stores test outputs and exit codes.

GitHub Actions cache is different

GitHub's cache uses immutable key-value pairs. It only writes a new blob if the job succeeds and there was no exact key match initially.

Job identity solves the race

cloudx-io/setup-go includes job identity in the cache key. Lint and test jobs now save and restore separate caches without conflicts.

Save cache on every run

By rendering exact key matches impossible, cloudx-io/setup-go ensures every job concludes with a freshly-written blob in the GitHub Actions cache service.

The new action writes a cache entry every time by including the run ID in the key. This preserves incremental work instead of discarding it.

The real-world impact

cloudx-io/setup-go speeds up parallel Golang CI workflows

When CloudX switched actions, median test runtime fell from 131 seconds to 41 seconds. That's a 69% improvement from one configuration change.

“cloudx-io/setup-go immediately cut test job runtimes by 69%.”

Fresh caches mean fewer tests

With the new strategy, the loaded cache is always fresh from the run before. Tests only run for packages genuinely modified by each commit.

86% reduction in test package runs

Backtesting 4,000 commits showed the new approach eliminated 86% of test package runs compared to the default action's behavior.

Two downsides to consider

Cache blobs can grow large since they're saved more often. You may need expanded GitHub Actions cache capacity, though faster jobs offset the cost.

The takeaway

Parallel CI jobs need separate cache keys to avoid racing and loading stale data that forces unnecessary retesting.

Read the original on CloudX | Ad Infrastructure for the Intelligence Era

React

Sign in to react and comment.

Comments (0)

Life is short. Keep it sweet. Respect others' opinions and be kind!

    Recommended next

    More decks on cloudx and related topics.