Render release descriptions before the save and limit release writes
What does this MR do and why?
Context
Creating or updating a release renders its description inside the save transaction, so a large description holds a database connection for the whole render. Nothing bounds how often one user or project writes releases. The figures and the agreed approach are in https://gitlab.com/gitlab-org/gitlab/-/work_items/638256#note_4182618868.
This MR
- The release services render the description before the save transaction and skip the save's own render, so the transaction holds only the writes. This covers a release that publishes to the CI/CD catalog, which saves inside the catalog version's transaction. The stored HTML is the same. A release that fails validation is not rendered first.
- Release creates and updates through the REST API and GraphQL
releaseCreateandreleaseUpdatecount toward two new rate limits, per project (release_writes_limit_per_project, default 300 per minute) and per user (release_writes_limit_per_user, default 600 per minute). Both arerate_limitsapplication settings on Admin > Settings > Network and in the application settings API, and0disables each. - The check runs after the access check, so users without access to a project don't spend its budget, and before any tag, render or catalog work. Refused and failed attempts count.
- Both keys start in log mode: writes over a limit are logged until that limit's flag is enabled, and then REST returns
429 Too Many Requestsand GraphQL returns an error. - Docs: a new rate limit page under
doc/rate_limits/api/, a line on the releases API, the settings API, and the GraphQL mutation descriptions. The Changelog entry comes with the flag-removal MR.
Feature Flag: release_description_render_before_save
Feature Flag: rate_limit_release_writes_per_project
Feature Flag: rate_limit_release_writes_per_user
References
- https://gitlab.com/gitlab-org/gitlab/-/work_items/638256+
- https://gitlab.com/gitlab-org/gitlab/-/work_items/639034+
Screenshots or screen recordings
The new Releases API rate limits block on Admin > Settings > Network. Before (master) and After (this branch) are attached at the end of this description.
How to set up and validate locally
- In a Rails console, set a small limit:
ApplicationSetting.current.update!(release_writes_limit_per_project: 1) - Wait a minute for the settings cache. With a personal access token (
apiscope) for a project where you can create releases, create two releases:Both returnfor tag in v-a v-b; do curl --include --request POST --header "PRIVATE-TOKEN: <your_access_token>" \ --data "tag_name=$tag&ref=<default_branch>&description=test" "http://gdk.test:3000/api/v4/projects/<id>/releases" done201, andlog/api_json.logshowsrate_limit_statewithlimit_release_writes_by_project_log:logfor the second request. - Run
Feature.enable(:rate_limit_release_writes_per_project), wait for the next minute, and repeat with new tags. The first returns201, the second429withRetry-After: 60. - Run
Feature.enable(:release_description_render_before_save)and create or update a release with a description.description_htmlmatches the same write with the flag off, and the request'sdb_main_txn_max_duration_sinlog/api_json.logno longer includes the render. - Clean up:
Feature.removethe two flags and reset the setting to300.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

