Building GitLab Pipelines That Fail Well
A practical system for fast, observable CI/CD pipelines that recover gracefully when infrastructure and dependencies misbehave.
By SibileshReliable delivery is less about making every job pass and more about making failure obvious, bounded, and inexpensive. A pipeline should tell an engineer what changed, where it broke, and whether retrying is safe.
Start with a visible contract
Every pipeline should have a small set of stages with explicit responsibilities:
stages: [verify, build, release]
quality:
stage: verify
script:
- go test -race ./...
- golangci-lint run
interruptible: true
image:
stage: build
needs: [quality]
script: docker build --tag "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA" .Keep the contract boring. A new contributor should understand the dependency graph in a minute.
Separate deterministic and environmental failures
Tests and static analysis are deterministic. Registry outages, rate limits, and transient network errors are environmental. Retrying both categories equally hides defects and wastes capacity.
| Failure | Retry? | Response |
|---|---|---|
| Unit test assertion | No | Fix the change |
| Runner system failure | Yes | Retry with a cap |
| Package checksum mismatch | No | Investigate supply chain |
| Registry 503 | Yes | Back off and retry |
Use retry: { max: 2, when: [runner_system_failure, api_failure] } so application failures remain visible.
Make the critical path measurable
Record queue time, execution time, cache hit rate, and time to first useful failure. Those four numbers reveal whether the bottleneck is capacity, work, or pipeline shape.
flowchart LR
Commit[Commit] --> Verify[Parallel verification]
Verify --> Build[Immutable build]
Build --> Scan[Security scan]
Scan --> Release[Protected release]Design for cancellation
Mark obsolete work as interruptible and use resource groups around stateful deployments. A newer commit should cancel work that can no longer reach production.
Production checklist
- Protected environments require approval.
- Build output is immutable and promoted, never rebuilt.
- Secrets are short-lived and scoped.
- Rollback has been tested, not merely documented.
The result is not a pipeline that never fails. It is a system that fails with enough context for the team to respond confidently.
Continue the discussion
Comments are enabled at deployment.
Configure the public Giscus environment variables to connect GitHub Discussions.