Closed blockers keep a wrong blocking count when the blocked issue is closed or reopened

Summary

Closing or reopening an issue recounts issues.blocking_issues_count for the issue and for its blockers in refresh_blocking_and_blocked_issues_cache!, but it takes the blockers from blocking_issues_ids, which returns only open ones. A closed blocker is not recounted, so its count stays too high when the issue it blocks is closed, and too low when that issue is reopened. GraphQL blockingCount, the work items REST API's blocking_count and the BLOCKING_ISSUES_* sorts read the column, for closed issues too.

This came up in the database review of !266012 (comment 4148836140), which found that it causes most of the wrong counts on GitLab.com.

Steps to reproduce

  1. On Premium or Ultimate, create issues A and B, and mark A as blocking B. A's blockingCount is 1.
  2. Close A, then close B.
  3. Query { project(fullPath: "<project_path>") { issue(iid: "<A>") { blockingCount } } }.
  4. With a new pair where A blocks B, close B, close A, then reopen B, and query A again.

Example Project

None on GitLab.com. Two model specs reproduce both cases on master at 5670247b.

What is the current bug behavior?

  • A blocks B, A is closed, then B is closed: A's blockingCount stays 1.
  • A blocks B, B is closed, A is closed, then B is reopened: A's blockingCount stays 0.

What is the expected correct behavior?

A's count follows the open issues it blocks, as blocking_issuables_for_collection counts them: 0 in the first case and 1 in the second.

Relevant logs and/or screenshots

The two specs on master
expected `blocking_issue1.reload.blocking_issues_count` to have changed from 1 to 0, but did not change
expected `blocking_issue1.reload.blocking_issues_count` to have changed from 0 to 1, but did not change

Output of checks

This bug happens on GitLab.com, as the review linked above found on a production clone. It is reproduced here in model specs.

Possible fixes

Recount every blocker from the blocks links that point at the issue, blocks.for_target(self) bounded by MAX_LINKS_COUNT, as the refresh on delete already does. Closed issues are to be kept up to date too, as confirmed in !266012 (comment 4190451933), and !266012 (merged) repairs the counts that are already wrong, after this fix.

I am opening a merge request with the fix suggested in that review.

Edited by 🤖 GitLab Bot 🤖