Stop coverage delta timeouts from breaking the MR widget
What does this MR do and why?
For some merge requests, widget.json returns HTTP 500 and the whole merge request widget fails to load. The cause is the base pipeline lookup behind the coverage delta shown next to test coverage in the widget: some projects build up many pipelines on one target-branch commit, and the existing index cannot serve that lookup efficiently, so it hits the database statement timeout.
MergeRequest#pipeline_coverage_deltareturns early when the head pipeline has no coverage, so the slow base pipeline lookup is skipped when there is nothing to compare.- The base pipeline lookup now runs under a 4.5 second statement timeout on the CI database, so a slow lookup fails fast instead of holding the request for 15 seconds.
MergeRequestPresenter#pipeline_coverage_deltacomputes the delta once instead of twice, and rescues errors: it logs them and returns nil, so the widget still loads without the delta.- The coverage delta moves from
widget.jsontocached_widget.json, so it is no longer recomputed on every poll, only when the merge request or its head pipeline changes. No frontend change is needed: the widget already fetches bothwidget.jsonandcached_widget.jsonand merges the two responses before readingpipeline_coverage_delta.
Database: the query itself is unchanged. It now runs inside a
transaction with SET LOCAL statement_timeout = 4500 on the CI
database, using the existing with_fast_read_statement_timeout
helper (which keeps reads on replicas). This is the helper's first
use with a Ci:: receiver. The lookup also no longer runs on every
widget poll.
Trade-off: a base pipeline that finishes after the last cache invalidation shows its delta on the next change to the merge request or its head pipeline, instead of within 10 seconds.
References
Resolves https://gitlab.com/gitlab-org/gitlab/-/work_items/630833
Screenshots or screen recordings
No visual change. Affected merge requests now load the widget without the coverage delta instead of failing.
How to set up and validate locally
- Use a merge request whose head pipeline and target-branch base
pipeline both have jobs with coverage. Set a job's coverage in
the rails console if needed, for example:
Ci::Build.find(<id>).update!(coverage: 90). - Open the merge request. The widget shows the coverage delta. In
the browser network tab,
cached_widget.jsonincludespipeline_coverage_deltaandwidget.jsonno longer does. - To simulate a slow base pipeline lookup, temporarily change
MergeRequest#base_pipelinein your GDK to runCi::Pipeline.connection.select_value('SELECT pg_sleep(5)')before its query, then restart Rails. - Reload the merge request. The widget loads without the delta,
and
log/exceptions_json.loghas anActiveRecord::QueryCanceledentry with the merge request ID. - Revert the temporary change.
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.