Skip to content

Cache the protected tag check

Vasilii Iakliushin requested to merge add_protected_tag_cache into master

Problem

We already cache protected branches checks, however we don't do that for tags.

Solution

After reviewing Caching guidelines I picked SafeRequestCache to reduce the number of SQL queries to protected_tags table. It should trigger only one SQL query to protected_tags during the request duration. Another option is to cache protected tag names in Redis (as it's done for protected_branches), but it adds extra load on Redis.

The default Rails SQL cache does not work in this case, because we specify select(:name) in association.

# Rails cache active 

[26] pry(main)> project.protected_tags
D, [2022-05-23T16:44:02.195087 #37353] DEBUG -- :   ProtectedTag Load (0.4ms)  SELECT "protected_tags".* FROM "protected_tags" WHERE "protected_tags"."project_id" = 59 /*application:console,db_config_name:main,line:bin/rails:4:in `<main>'*/
=> []
[27] pry(main)> project.protected_tags
=> []
# Note: ProtectedTag Load line is missing for the second request, because it was cached.

# Rails cache does not work

[28] pry(main)> project.protected_tags.select(:name)
D, [2022-05-23T16:44:49.488279 #37353] DEBUG -- :   ProtectedTag Load (0.4ms)  SELECT "protected_tags"."name" FROM "protected_tags" WHERE "protected_tags"."project_id" = 59 /*application:console,db_config_name:main,line:bin/rails:4:in `<main>'*/
=> []
[29] pry(main)> project.protected_tags.select(:name)
D, [2022-05-23T16:44:50.598066 #37353] DEBUG -- :   ProtectedTag Load (0.4ms)  SELECT "protected_tags"."name" FROM "protected_tags" WHERE "protected_tags"."project_id" = 59 /*application:console,db_config_name:main,line:bin/rails:4:in `<main>'*/
=> []

The lack of cache generates extra N requests to database when we create new tags for mirror updates, for example. We trigger a new request to protected_tags table for each new tag created.

Edited by Vasilii Iakliushin

Merge request reports