← all posts

Faster CI with a Rust-based cache layer

How I cut build times 60% by rewriting the cache layer that sat between CI and object storage.

Our CI spent more time downloading caches than building. The culprit was a Python shim doing synchronous, un-deduplicated uploads. I rewrote it in Rust over a weekend.

Content-addressed, concurrent

Every artifact is keyed by the hash of its inputs. If the hash exists, we skip the upload entirely — and we do the existence checks concurrently with tokio.

cache.rs
rust
pub async fn store(items: Vec<Artifact>) -> Result<()> {
    let tasks = items.into_iter().map(|a| async move {
        if !exists(&a.key).await? {
            upload(&a).await?;
        }
        Ok(())
    });
    try_join_all(tasks).await?;
    Ok(())
}

The result: a p50 cache step that went from 90s to 34s. The numbers that mattered weren’t CPU — they were the requests we didn’t make.

// up next