Loading
Add per-user rate limits to job erasure
What does this MR do and why?
This MR adds per-user rate limits to job erasure in Ci::BuildEraseService. The limit check
runs first, so a rejected call is still counted against the limit.
- Per user and job: 5 requests a minute, fixed.
- Per user and project: configurable (
job_erase_limit_per_user_project), default 400 a minute,0disables it.
A blocked request gets a 429 with a Retry-After header from the REST API, and a 429 JSON
response or a flash alert from the jobs controller. There is no GraphQL mutation for erasing a
job. The limit is behind the rate_limit_job_erase feature flag, disabled by default.
References
- https://gitlab.com/gitlab-org/gitlab/-/work_items/627274
- Job retry and play limits, same pattern: !256678 (merged)
- Job cancellation limit (companion MR): !259438
Design notes
Ci::BuildEraseServiceis the only seam: both doors (REST and the jobs controller) already call it, and nothing else does.- Rejections at the door happen before the service runs, so they are not counted. For example,
the REST endpoint's 403 for a non-erasable job and the controller's
before_actionpermission check. This matches how the retry and play limits behave. Ci::JobRateLimitablegains a defaultrate_limit?oftrue, so services without internal callers do not have to define it. The companion cancellation MR makes the same small change, so whichever merges second needs a rebase.
How to set up and validate locally
- In a rails console, enable the flag:
Feature.enable(:rate_limit_job_erase). - In Admin > Settings > CI/CD > Continuous Integration and Deployment, lower Maximum job erasures per project.
- Erase jobs from the UI, or call
POST /api/v4/projects/:id/jobs/:job_id/erase, more times than the limit within a minute. - Confirm you get a 429 with a
Retry-Afterheader from the API, or a flash alert from the UI.
MR acceptance checklist
- This MR meets the MR acceptance checklist.
Edited by Shabini Rajadas