Overview
Pipelines-as-Code provides concurrency control to limit the number of PipelineRuns that can execute simultaneously for a repository. This prevents resource exhaustion when multiple events trigger pipelines at the same time.Configuration
Repository-Level Concurrency Limit
Setconcurrency_limit in the Repository CR to define the maximum number of concurrent PipelineRuns:
Maximum number of PipelineRuns that can run concurrently for this repository.
- Minimum value: 1
- Default: No limit (all matching PipelineRuns start immediately)
- Applies to: All PipelineRuns triggered by events in this repository
How It Works
When a Git event triggers multiple PipelineRuns:- Without concurrency limit: All PipelineRuns start immediately
- With concurrency limit:
- Up to
concurrency_limitPipelineRuns start immediately - Remaining PipelineRuns are queued
- Queued PipelineRuns start as running ones complete
- PipelineRuns execute in alphabetical order by name
- Up to
Execution Order
PipelineRuns are started in alphabetical order:concurrency_limit: 2:
a-unit-testsandb-integration-testsstart immediatelyc-e2e-testsandd-security-scanare queued- When
a-unit-testscompletes,c-e2e-testsstarts - When
b-integration-testscompletes,d-security-scanstarts
Use alphabetical naming (e.g.,
01-, 02-, etc.) to control execution order when using concurrency limits.Use Cases
Resource-Constrained Clusters
Resource-Constrained Clusters
Cost Optimization
Cost Optimization
Ordered Execution for Monorepo
Ordered Execution for Monorepo
01-lint.yaml02-unit-tests.yaml03-integration-tests.yaml04-build.yaml
External Service Rate Limiting
External Service Rate Limiting
Example: Pull Request with Multiple Pipelines
Given this.tekton directory:
pull_request events.
Without concurrency limit:
integration-testsstarts (alphabetically first)lintis queuedunit-testsis queued- When
integration-testscompletes,lintstarts - When
lintcompletes,unit-testsstarts
Queue Behavior
Queued PipelineRun States
- Running: Currently executing (up to
concurrency_limit) - Pending: Queued, waiting for a slot (shown with Pending status)
- Unknown: May appear briefly during state transitions
Viewing Queue Status
Queue Skipping
PAC skips PipelineRuns in these states when checking the queue:- Running: Actively executing
- Pending: Waiting in queue
Global vs Repository Configuration
Concurrency can be configured at two levels:Repository Level (Recommended)
Global Level (via ConfigMap)
Configure a default for all repositories:Interaction with Other Features
Concurrency + cancel-in-progress
This annotation automatically cancels in-progress runs when a new commit is pushed:cancel-in-progresstakes precedenceconcurrency_limitis ignored- You’ll see a warning in the PAC controller logs
Concurrency + max-keep-runs
These features work together:concurrency_limit: Controls how many run simultaneouslymax-keep-runs: Controls how many completed runs are retained
Kubernetes-Native Queueing with Kueue
For more advanced queueing scenarios, PAC integrates with Kueue:- Fair-sharing between multiple repositories
- Priority-based scheduling
- Resource quotas and preemption
- Integration with cluster autoscaling
Experimental: Kueue integration via konflux-ci/tekton-kueue is for testing only and not recommended for production.
Troubleshooting
PipelineRuns Stay Pending Forever
PipelineRuns Stay Pending Forever
Possible causes:
- Another PipelineRun is stuck in Running state
- Concurrency limit set too low
- Cluster resource constraints preventing execution
PipelineRuns Execute Out of Order
PipelineRuns Execute Out of Order
Cause: PipelineRuns are executed in alphabetical order by nameSolution: Use prefixes to control order:
Concurrency Limit Not Applied
Concurrency Limit Not Applied
Possible causes:
concurrency_limitnot set in Repository CR- Typo in field name (check YAML)
- Repository CR not in correct namespace
- Using
cancel-in-progressannotation
Too Many PipelineRuns Running
Too Many PipelineRuns Running
Cause: Concurrency limit applies per Repository, not globallyExample: 3 repositories each with
concurrency_limit: 5 = up to 15 total concurrent runsSolution:- Reduce per-repository limits
- Use global ConfigMap default
- Implement Kueue for cluster-wide quotas
Best Practices
- Start Conservative: Begin with low limits and increase based on monitoring
- Monitor Resource Usage: Track CPU, memory, and storage to determine optimal limits
-
Name for Order: Use numerical prefixes when execution order matters:
-
Consider Dependencies: If pipelines depend on each other, use
concurrency_limit: 1 -
Different Limits per Repo: Heavy builds might need
limit: 1, light tests can uselimit: 5 - Document Limits: Add comments explaining why specific limits were chosen
- Test Queue Behavior: Manually trigger multiple pipelines to verify queueing works as expected
- Alert on Long Queues: Monitor Pending PipelineRuns and alert if queues grow too large
Performance Considerations
High Concurrency (No Limit)
High Concurrency (No Limit)
Pros:
- Fastest feedback for developers
- No waiting in queue
- May overwhelm cluster resources
- Higher cloud costs
- Risk of resource exhaustion
Medium Concurrency (limit: 3-5)
Medium Concurrency (limit: 3-5)
Pros:
- Balanced resource usage
- Predictable costs
- Still provides reasonable feedback time
- Some queueing during high activity
- Requires capacity planning
Low Concurrency (limit: 1-2)
Low Concurrency (limit: 1-2)
Pros:
- Minimal resource usage
- Strict cost control
- Ensures execution order
- Longest wait times
- Can bottleneck development
Example Configurations
Multi-Stage Pipeline with Dependencies
Multi-Stage Pipeline with Dependencies
Large Monorepo with Multiple Teams
Large Monorepo with Multiple Teams
Cost-Optimized Cloud Builds
Cost-Optimized Cloud Builds
See Also
- Repository CRD - Complete Repository configuration reference
- Cleanup - Automatic cleanup and retention policies
- Running PipelineRuns - How PipelineRuns are triggered and managed
- Kueue Documentation - Advanced Kubernetes-native job queueing