Batch update merge_status during refresh_service

What does this MR do and why?

When pushing to a repository, the MergeRequests::RefreshService needs to update the merge_status of all affected merge requests. Currently, this is done via individual mark_as_unchecked calls on each MR which could potentially be thousands of MRs on busy project. Also, since it's possible that it may have to process many merge requests so we're processing 1000 at a time.

While it's not ideal we are by passing the state machine, but I think gain outweighs potential issues. It's gated by batch_merge_status_updates feature flag.

This would likely reduce the number of merge_status update queries significantly and will contribute towards lowering WAL rate generation coming from this query.

References

How to set up and validate locally

  1. Create several merge requests on a project
  2. Grep logs to see merge_status update queries.
    tail -f log/development.log | grep 'UPDATE "merge_requests" SET "merge_status" ='
  3. Ensure that all merge requests are not in unchecked status
    project = Project.find(YOUR_PROJECT_ID)
    project.merge_requests.opened.each {|mr| mr.check_mergeability}
    # Verify the status by examining the `merge_status` of each merge requests
    project.merge_requests.opened.map {|a| a.reload; p [a.id, a.merge_status, a.title]}
  4. Make a direct code change to the target branch via UI or console and push it up.
  5. Observe several merge_status update calls firing vi the log above
  6. Now, In rails console enable the feature flag
    Feature.enable(:batch_merge_status_updates)
  7. Follow the same steps as above and observe there are now only 2 batched update queries for new commit to the target branch.

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.

Related to #546431

Edited by Sincheol (David) Kim

Merge request reports

Loading