Optimize: custom ability verification
What does this MR do and why?
Contributes to #482942 (closed)
Problem
We use Authz::CustomAbility.allowed? to check custom abilities of the
user. But for each ability we trigger two database requests to fetch
the same project and namespace. That leads to N+1 problem.
Solution
- Restructure
Authz::CustomAbilityto support caching.
The code below won't trigger unnecessary database queries for each
allowed? call.
ability = Authz::CustomAbility.new(user, project)
ability.allowed?(:ability_1)
ability.allowed?(:ability_2)
- Add caching level to the policy code
Authz::CustomAbility record will be memoized and have access to
permitted abilities to optimize the number of DB queries.
References
Please include cross links to any resources that are relevant to this MR This will give reviewers and future readers helpful context to give an efficient review of the changes introduced.
MR acceptance checklist
Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Screenshots or screen recordings
graph TB
ProjectPolicy
Authz::CustomAbility
Authz::Project
Preloaders::UserMemberRolesInProjectsPreloader
Preloaders::ProjectRootAncestorPreloader
ProjectPolicy ---> Authz::CustomAbility
Authz::CustomAbility --> Authz::Project
Authz::Project --> Preloaders::UserMemberRolesInProjectsPreloader
Preloaders::UserMemberRolesInProjectsPreloader --> Preloaders::ProjectRootAncestorPreloader
- In
ProjectPolicywe define a condition for each custom ability. - Each
Authz::CustomAbilityrequests a list of permitted abilitiesAuthz::Project#permitted -
Preloaders::ProjectRootAncestorPreloaderis called for eachAuthz::Project#permittedand triggers two DB queries for each ability checked.
For some pages it leads to 32 additional requests to projects and namespaces tables.