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_delta returns 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_delta computes 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.json to cached_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 both widget.json and cached_widget.json and merges the two responses before reading pipeline_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

  1. 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).
  2. Open the merge request. The widget shows the coverage delta. In the browser network tab, cached_widget.json includes pipeline_coverage_delta and widget.json no longer does.
  3. To simulate a slow base pipeline lookup, temporarily change MergeRequest#base_pipeline in your GDK to run Ci::Pipeline.connection.select_value('SELECT pg_sleep(5)') before its query, then restart Rails.
  4. Reload the merge request. The widget loads without the delta, and log/exceptions_json.log has an ActiveRecord::QueryCanceled entry with the merge request ID.
  5. 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.

Merge request reports

Loading
Loading