stamatios
← Voltar ao feed
Esteira de linha de montagem acelerando com caixas se multiplicando, metáfora do CI refeito pela Linear para PRs mais rápidos
Dev & Engenharia

Linear refez o CI para acompanhar a era do coding com IA

resumo de ~3 min

CI como gargalo da era dos agentes

A Linear publicou um relato interno de engenharia sobre por que e como refez seu pipeline de CI. O ponto de partida foi uma tarefa atribuída pelo CTO, Tuomas, ao engenheiro Mufeez Amjad, com o título "custos de CI estão altos" - e a meta adicional de tornar o CI mais rápido. A justificativa: agentes de codificação aceleraram exponencialmente o envio de código, mas a validação não acompanhou. Como todo pull request passa pelo CI, o aumento de velocidade de desenvolvimento transforma o CI em gargalo, elevando custos de infraestrutura e fazendo humanos e agentes esperarem mais por feedback.

As métricas de otimização foram o tempo que um PR espera no CI e o tempo de runner consumido. Resultado: apesar de a suíte de testes quase quadruplicar desde o início do ano, o tempo de espera por PR caiu de mais de 6 minutos para pouco acima de 5, e o tempo de runner por teste caiu aproximadamente pela metade.

Infraestrutura e toolchain

Os primeiros ganhos vieram sem otimizar o CI em si: migrar de GitHub Actions para runners de terceiros com CPUs mais rápidas, armazenamento de melhor desempenho e melhor infraestrutura de cache fez os jobs rodarem 34% mais rápido em comparação direta entre os dois dias da troca, com alguns workloads como o tsc caindo 52%. A adoção do tsgo, o compilador nativo de TypeScript, cortou a mediana semanal do check de tsc em 73%, tirando o gargalo do typechecking.

No lint, regras customizadas que dependiam de informações de tipos foram reescritas para análise estática sobre a árvore sintática, eliminando a dependência do TypeScript no ESLint: o lint de API caiu 68% e o lint do repositório inteiro, 55%, com grande redução de memória. Isso também facilitou a migração posterior para Oxlint.

Otimizar os jobs que bloqueiam os demais

Olhando o CI como sistema, a equipe atacou os pequenos jobs de verificação de caminhos e de cache que ficavam no caminho crítico - todos os oito shards de testes de API esperavam por eles. Limitar a profundidade de fetch tirou o pior desses jobs de 94 para 20 segundos; remover o checkout de jobs sem necessidade reduziu de 27 para 7 segundos; e um checkout sparse e blobless para eventos de push e merge queue poupou mais 11 segundos. A mediana do job de detecção de mudanças caiu de 26 para 8 segundos e o pior caso, de 138 para 37.

Após a troca de runners, o checkout passou a travar ocasionalmente, porque os runners de terceiros ficam fora da rede do GitHub e dependem de um link IP direto com degradação intermitente. A Linear substituiu actions/checkout por uma ação própria com retry com backoff, limites de velocidade (GIT_HTTP_LOW_SPEED_LIMIT/TIME) para abortar conexões paradas após cerca de 30 segundos e cache de checkout com um espelho git persistente.

Outra mudança removeu do caminho crítico a escrita de marcadores de cache, poupando 42 segundos no caminho de merge; no total, cerca de um minuto foi tirado do check obrigatório de PRs de API em cache misses.

Reduzir setup repetido

As otimizações de setup cobriram: pré-instalar o cliente Postgres em uma imagem base de CI; instalar apenas as dependências de cada job (o pnpm install do workflow de API caiu de 44-73 para 16-18 segundos); e descartar o cache de node_modules, pois a restauração levava cerca de 28 segundos contra 7,5 de um install filtrado. Juntas, essas medidas cortaram cerca de 44% do setup por shard, de 110-140 para 67-73 segundos. Além disso, containers de API passaram a carregar um snapshot de schema em vez de reexecutar migrações quando o PR não mudava o banco (de 12 para 1-2 segundos), e sete checks curtos independentes foram consolidados em dois jobs - economia estimada de 87 mil runner-minutos mensais, 11,8% do uso total de CI.

Execução de testes mais eficiente

Com o custo fixo menor, a suíte de API (escrita em Vitest) pôde ser paralelizada de três para quatro e depois oito shards, 19% mais rápido e mais barato no benchmark inicial. O Vitest distribui por arquivo, então arquivos grandes foram divididos; a semana seguinte viu o shard mais lento cair de 5,25 para 4,33 minutos. A maior melhoria individual foi um projeto Vitest opt-in com isolate: false, permitindo que arquivos seguros compartilhem o registro de módulos: cerca de 17% de economia mensal, com o shard mais lento caindo de 300-379 para cerca de 195 segundos e o tempo total de runner por execução de 32,8 para 22 minutos. Foi também a otimização de maior risco de corretude: a elegibilidade é marcada por comentário em cada arquivo, arquivos com timers falsos ou estado compartilhado ficaram isolados, e as skills dos agentes de código foram atualizadas para gerar testes dentro dessas restrições - já que agentes escrevem a maioria dos testes da empresa.

A equipe nota que o sharding só compensa quando o setup por shard é barato: com o setup antigo, oito shards gastariam 15-19 minutos só de setup; hoje, com cerca de 40 segundos por shard, oito gastam menos setup do que quatro gastavam antes. Sem o esforço do ano, a suíte atual levaria cerca de 11 minutos, quase o dobro da espera atual. Com cerca de 2.000 testes novos por semana, a Linear trata a manutenção da velocidade do CI como esforço contínuo.