Loading
Detect database writes on HTTP GET requests
What does this MR do and why?
In incident INC-12449, a GET endpoint wrote to the database on every call and overloaded the primary under burst traffic. Nothing currently stops a GET endpoint from writing. This MR adds a query analyzer to detect writes on GET requests, following the PreventCrossDatabaseModification playbook. It is a detection step. Enforcement is a later step.
How it works:
Gitlab::Middleware::QueryAnalyzernow records the HTTP method in the request store before analyzers run. The new analyzer'senabled?reads this once per request. Zero cost for non-GET requests and Sidekiq.- New
PreventWritesOnGetanalyzer detects INSERT/UPDATE/DELETE (and SELECT FOR UPDATE) on GET/HEAD requests, using a regex pre-filter plus pg_query. It only logswrite_on_get_detected, behind thedetect_writes_on_getops flag, in every environment. It never raises. This was a deliberate choice after review feedback, to avoid breaking pipelines of unrelated merge requests. - Logging goes through a dedicated logger,
PreventWritesOnGet::Logger, aGitlab::JsonLoggerwithexclude_context!, writing todatabase_writes_on_get. The dedicated logger avoidsGitlab::AppLogger, which merges the lazy Labkit context into every line and memoizes attributes likemeta.userbefore the controller assigns them. Thecaller_idin the payload already identifies the endpoint. - An endpoint allowlist is seeded with the known production violators, roughly 6 million writes-on-GET requests per week, led by the merge request view, repository archive download, and dependency proxy cache miss. The analyzer returns early for these endpoints and does not log them at all. This way the log only shows writes on GET that are not yet known, so it works as a detector of new cases. Fixing the known violators is out of scope, burn-down issues per owning group will follow.
- Two sanctioned throttled writes (
Users::ActivityService,PersonalAccessTokens::LastUsedService) use a newallow_write_on_get(url:)helper.
References
- Issue: #608670 (closed)
- Corrective action: gitlab-com/gl-infra/production-engineering#29434 (closed)
- Immediate fix: !247205 (merged)
- Volume analysis: gitlab-com/gl-infra/production-engineering#29434 (comment 3613231020)
How to set up and validate locally
Run:
bundle exec rspec spec/lib/gitlab/database/query_analyzers/prevent_writes_on_get_spec.rb spec/lib/gitlab/middleware/query_analyzer_spec.rbIn GDK, a GET request that writes to the database is logged to database_writes_on_get when the detect_writes_on_get ops flag is enabled.
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.
Edited by Leonardo da Rosa