Use etag caching for Projects::MergeRequestsController#show widget serializer
Problem to solve
On every merge request page, frontend periodically (every 10 seconds by default) polls merge_requests/<id>.json?serializer=widget
for changes. This query is very expensive because this widget contains a lot of information.
It also calls multiple gitaly calls (https://gitlab.com/gitlab-org/gitlab-ce/issues/37432#note_162513930) which is even more expensive for users using NFS storage.
Frequency of calls on gitlab.com:
- json widget: https://log.gitlab.net/app/kibana#/discover/AWqSESGoLHa0LJnq82bT?_g=()
- loading MR's html show page: https://log.gitlab.net/app/kibana#/discover/AWqSEnAALHa0LJnq9pDc?_g=()
Proposal
We could use etag caching for caching the whole request, as we already use this caching for some other endpoints. Etag cache would be invalidated when the merge request is changed or when other resources related to the merge request are changed.
The benefit is that it's easy to set up (as we already use it for other endpoints) and has big positive performance impact.
The challenging part is to make sure that we invalidate/expire etag cache key in all situations relevant to the merge request widget, but not impossible I think. Also this caching would be used for async polling only, if user reloads page he would always get fresh data, so even if we would forget about some situation when key should be invalidate, it's not a fatal problem.
We would also have to change the MR's widget path because currently etag caching doesn't support parameters (we use ?serializer=widget
), or we would have to fix https://gitlab.com/gitlab-org/gitlab-ce/issues/58500 first. This is tracked by https://gitlab.com/gitlab-org/gitlab-ce/issues/62723 - which is prerequisite of this issue.