Skip to content

GraphQL: Fix N+1 issue in RunnerOwnerProjectResolver

What does this MR do and why?

Describe in detail what your merge request does and why.

This MR adds support for preloading relationships for fullPath and webUrl properties, which are in use for the Runners' admin UI.

Part of #384066 (closed) and #385355 (closed)

Screenshots or screen recordings

Screenshots are required for UI changes, and strongly recommended for all other merge requests.

How to set up and validate locally

Numbered steps to set up and validate the change are strongly suggested.

  1. Visit http://gdk.test:3000/-/graphql-explorer

  2. Run the following query:

    {
      runners(type: PROJECT_TYPE, last: 20) {
        count
        nodes {
          id
          runnerType
          ownerProject {
            id
            fullPath
            webUrl
          }
        }
      }
    }

The queries generated by this branch should no longer generate a route query per-runner.

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Database queries

Old queries
Processing by GraphqlController#execute as */*
  Parameters: {"query"=>"{\n  runners(type: PROJECT_TYPE, last: 20) {\n    count\n    nodes {\n      id\n      runnerType\n      ownerProject {\n        id\n        fullPath\n        webUrl\n      }\n    }\n  }\n}\n", "variables"=>"[FILTERED]", "graphql"=>{"query"=>"{\n  runners(type: PROJECT_TYPE, last: 20) {\n    count\n    nodes {\n      id\n      runnerType\n      ownerProject {\n        id\n        fullPath\n        webUrl\n      }\n    }\n  }\n}\n", "variables"=>"[FILTERED]"}}
   (0.3ms)  SELECT COUNT(*) FROM "ci_runners" WHERE "ci_runners"."runner_type" = 3 /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:graphql:unknown,db_config_name:ci,line:/app/graphql/types/countable_connection_type.rb:20:in `count'*/
  ↳ app/graphql/types/countable_connection_type.rb:20:in `count'
  Ci::Runner Load (0.2ms)  SELECT "ci_runners".* FROM "ci_runners" WHERE "ci_runners"."runner_type" = 3 ORDER BY "ci_runners"."created_at" ASC, "ci_runners"."id" ASC LIMIT 21 /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:graphql:unknown,db_config_name:ci,line:/lib/gitlab/graphql/pagination/keyset/connection.rb:114:in `block in limited_nodes'*/
  ↳ lib/gitlab/graphql/pagination/keyset/connection.rb:114:in `block in limited_nodes'
  Ci::RunnerProject Load (0.2ms)  SELECT "id", "runner_id", "project_id" FROM (SELECT id, runner_id, project_id, ROW_NUMBER() OVER (PARTITION BY runner_id ORDER BY id ASC) FROM "ci_runner_projects" WHERE "ci_runner_projects"."runner_id" IN (97978, 97977, 1227, 1226, 1225, 1224, 1223, 1222, 1221, 1220)) temp WHERE row_number = 1 /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:GraphqlController#execute,db_config_name:ci,line:/app/graphql/resolvers/ci/runner_owner_project_resolver.rb:47:in `group_by'*/
  ↳ app/graphql/resolvers/ci/runner_owner_project_resolver.rb:47:in `group_by'
  Project Load (0.4ms)  SELECT "projects".* FROM "projects" WHERE "projects"."id" IN (20, 23) /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_policy_preloader.rb:13:in `execute'*/
   app/models/preloaders/project_policy_preloader.rb:13:in `execute'
  Group Load (0.3ms)  SELECT "namespaces"."id", "namespaces"."name", "namespaces"."path", "namespaces"."owner_id", "namespaces"."created_at", "namespaces"."updated_at", "namespaces"."type", "namespaces"."description", "namespaces"."avatar", "namespaces"."membership_lock", "namespaces"."share_with_group_lock", "namespaces"."visibility_level", "namespaces"."request_access_enabled", "namespaces"."ldap_sync_status", "namespaces"."ldap_sync_error", "namespaces"."ldap_sync_last_update_at", "namespaces"."ldap_sync_last_successful_update_at", "namespaces"."ldap_sync_last_sync_at", "namespaces"."description_html", "namespaces"."lfs_enabled", "namespaces"."parent_id", "namespaces"."shared_runners_minutes_limit", "namespaces"."repository_size_limit", "namespaces"."require_two_factor_authentication", "namespaces"."two_factor_grace_period", "namespaces"."cached_markdown_version", "namespaces"."project_creation_level", "namespaces"."runners_token", "namespaces"."file_template_project_id", "namespaces"."saml_discovery_token", "namespaces"."runners_token_encrypted", "namespaces"."custom_project_templates_group_id", "namespaces"."auto_devops_enabled", "namespaces"."extra_shared_runners_minutes_limit", "namespaces"."last_ci_minutes_notification_at", "namespaces"."last_ci_minutes_usage_notification_level", "namespaces"."subgroup_creation_level", "namespaces"."emails_disabled", "namespaces"."max_pages_size", "namespaces"."max_artifacts_size", "namespaces"."mentions_disabled", "namespaces"."default_branch_protection", "namespaces"."unlock_membership_to_ldap", "namespaces"."max_personal_access_token_lifetime", "namespaces"."push_rule_id", "namespaces"."shared_runners_enabled", "namespaces"."allow_descendants_override_disabled_shared_runners", "namespaces"."traversal_ids" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" IN (22, 80) /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_policy_preloader.rb:13:in `execute'*/
  ↳ app/models/preloaders/project_policy_preloader.rb:13:in `execute'
  Route Load (0.2ms)  SELECT "routes".* FROM "routes" WHERE "routes"."source_type" = 'Namespace' AND "routes"."source_id" IN (22, 80) /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_policy_preloader.rb:13:in `execute'*/
   app/models/preloaders/project_policy_preloader.rb:13:in `execute'
  Namespace Load (0.2ms)  SELECT "namespaces"."id", "namespaces"."name", "namespaces"."path", "namespaces"."owner_id", "namespaces"."created_at", "namespaces"."updated_at", "namespaces"."type", "namespaces"."description", "namespaces"."avatar", "namespaces"."membership_lock", "namespaces"."share_with_group_lock", "namespaces"."visibility_level", "namespaces"."request_access_enabled", "namespaces"."ldap_sync_status", "namespaces"."ldap_sync_error", "namespaces"."ldap_sync_last_update_at", "namespaces"."ldap_sync_last_successful_update_at", "namespaces"."ldap_sync_last_sync_at", "namespaces"."description_html", "namespaces"."lfs_enabled", "namespaces"."parent_id", "namespaces"."shared_runners_minutes_limit", "namespaces"."repository_size_limit", "namespaces"."require_two_factor_authentication", "namespaces"."two_factor_grace_period", "namespaces"."cached_markdown_version", "namespaces"."project_creation_level", "namespaces"."runners_token", "namespaces"."file_template_project_id", "namespaces"."saml_discovery_token", "namespaces"."runners_token_encrypted", "namespaces"."custom_project_templates_group_id", "namespaces"."auto_devops_enabled", "namespaces"."extra_shared_runners_minutes_limit", "namespaces"."last_ci_minutes_notification_at", "namespaces"."last_ci_minutes_usage_notification_level", "namespaces"."subgroup_creation_level", "namespaces"."emails_disabled", "namespaces"."max_pages_size", "namespaces"."max_artifacts_size", "namespaces"."mentions_disabled", "namespaces"."default_branch_protection", "namespaces"."unlock_membership_to_ldap", "namespaces"."max_personal_access_token_lifetime", "namespaces"."push_rule_id", "namespaces"."shared_runners_enabled", "namespaces"."allow_descendants_override_disabled_shared_runners", "namespaces"."traversal_ids" FROM "namespaces" WHERE "namespaces"."id" IN (22, 80) /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_policy_preloader.rb:13:in `execute'*/
  ↳ app/models/preloaders/project_policy_preloader.rb:13:in `execute'
  Project Load (0.5ms)  SELECT "projects".*, "project_authorizations"."user_id", "project_authorizations"."access_level" FROM "projects" LEFT OUTER JOIN "project_authorizations" AS project_authorizations ON "project_authorizations"."project_id" = "projects"."id" AND "project_authorizations"."user_id" = 1 WHERE "projects"."id" IN (20, 23) /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/user_max_access_level_in_projects_preloader.rb:34:in `execute'*/
   app/models/preloaders/user_max_access_level_in_projects_preloader.rb:34:in `execute'
  Namespace Load (0.7ms)  SELECT namespaces.*, root_query.id as source_id FROM "namespaces" INNER JOIN (SELECT projects.id, namespaces.traversal_ids[1] as root_id FROM "projects" INNER JOIN "namespaces" ON "namespaces"."type" = 'Group' AND "namespaces"."id" = "projects"."namespace_id" AND "namespaces"."type" = 'Group' WHERE "projects"."id" IN (20, 23)) as root_query ON root_query.root_id = namespaces.id /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_root_ancestor_preloader.rb:20:in `group_by'*/
  ↳ app/models/preloaders/project_root_ancestor_preloader.rb:20:in `group_by'
  IpRestriction Load (0.2ms)  SELECT "ip_restrictions".* FROM "ip_restrictions" WHERE "ip_restrictions"."group_id" IN (22, 79) /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_root_ancestor_preloader.rb:20:in `group_by'*/
   app/models/preloaders/project_root_ancestor_preloader.rb:20:in `group_by'
  SamlProvider Load (0.1ms)  SELECT "saml_providers".* FROM "saml_providers" WHERE "saml_providers"."group_id" IN (22, 79) /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_root_ancestor_preloader.rb:20:in `group_by'*/
  ↳ app/models/preloaders/project_root_ancestor_preloader.rb:20:in `group_by'
  Route Load (0.2ms)  SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 23 AND "routes"."source_type" = 'Project' LIMIT 1 /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/concerns/routable.rb:121:in `full_path'*/
   app/models/concerns/routable.rb:121:in `full_path'
  Route Load (0.2ms)  SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 80 AND "routes"."source_type" = 'Namespace' LIMIT 1 /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/concerns/routable.rb:121:in `full_path'*/
  ↳ app/models/concerns/routable.rb:121:in `full_path'
  Route Load (0.2ms)  SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 20 AND "routes"."source_type" = 'Project' LIMIT 1 /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/concerns/routable.rb:121:in `full_path'*/
   app/models/concerns/routable.rb:121:in `full_path'
  Route Load (0.2ms)  SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 22 AND "routes"."source_type" = 'Namespace' LIMIT 1 /*application:web,correlation_id:01GM3GGPVG7JJDXD8JHYP21YSC,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/concerns/routable.rb:121:in `full_path'*/
  ↳ app/models/concerns/routable.rb:121:in `full_path'
Completed 200 OK in 70ms (Views: 0.2ms | ActiveRecord: 4.2ms | Elasticsearch: 0.0ms | Allocations: 88998)
New queries
Processing by GraphqlController#execute as */*
  Parameters: {"query"=>"{\n  runners(type: PROJECT_TYPE, last: 20) {\n    count\n    nodes {\n      id\n      runnerType\n      ownerProject {\n        id\n        fullPath\n        webUrl\n      }\n    }\n  }\n}\n", "variables"=>"[FILTERED]", "graphql"=>{"query"=>"{\n  runners(type: PROJECT_TYPE, last: 20) {\n    count\n    nodes {\n      id\n      runnerType\n      ownerProject {\n        id\n        fullPath\n        webUrl\n      }\n    }\n  }\n}\n", "variables"=>"[FILTERED]"}}
   (0.3ms)  SELECT COUNT(*) FROM "ci_runners" WHERE "ci_runners"."runner_type" = 3 /*application:web,correlation_id:01GM3GFCYFJD458FZZ4RPPY46N,endpoint_id:graphql:unknown,db_config_name:ci,line:/app/graphql/types/countable_connection_type.rb:20:in `count'*/
  ↳ app/graphql/types/countable_connection_type.rb:20:in `count'
  Ci::Runner Load (0.4ms)  SELECT "ci_runners".* FROM "ci_runners" WHERE "ci_runners"."runner_type" = 3 ORDER BY "ci_runners"."created_at" ASC, "ci_runners"."id" ASC LIMIT 21 /*application:web,correlation_id:01GM3GFCYFJD458FZZ4RPPY46N,endpoint_id:graphql:unknown,db_config_name:ci,line:/lib/gitlab/graphql/pagination/keyset/connection.rb:114:in `block in limited_nodes'*/
  ↳ lib/gitlab/graphql/pagination/keyset/connection.rb:114:in `block in limited_nodes'
  Ci::RunnerProject Load (0.3ms)  SELECT "id", "runner_id", "project_id" FROM (SELECT id, runner_id, project_id, ROW_NUMBER() OVER (PARTITION BY runner_id ORDER BY id ASC) FROM "ci_runner_projects" WHERE "ci_runner_projects"."runner_id" IN (97978, 97977, 1227, 1226, 1225, 1224, 1223, 1222, 1221, 1220)) temp WHERE row_number = 1 /*application:web,correlation_id:01GM3GFCYFJD458FZZ4RPPY46N,endpoint_id:GraphqlController#execute,db_config_name:ci,line:/app/graphql/resolvers/ci/runner_owner_project_resolver.rb:49:in `group_by'*/
  ↳ app/graphql/resolvers/ci/runner_owner_project_resolver.rb:49:in `group_by'
  Project Load (0.7ms)  SELECT "projects".* FROM "projects" WHERE "projects"."id" IN (20, 23) /*application:web,correlation_id:01GM3GFCYFJD458FZZ4RPPY46N,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_policy_preloader.rb:13:in `execute'*/
   app/models/preloaders/project_policy_preloader.rb:13:in `execute'
  ProjectFeature Load (0.3ms)  SELECT "project_features".* FROM "project_features" WHERE "project_features"."project_id" IN (20, 23) /*application:web,correlation_id:01GM3GFCYFJD458FZZ4RPPY46N,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_policy_preloader.rb:13:in `execute'*/
  ↳ app/models/preloaders/project_policy_preloader.rb:13:in `execute'
  Route Load (0.3ms)  SELECT "routes".* FROM "routes" WHERE "routes"."source_type" = 'Project' AND "routes"."source_id" IN (20, 23) /*application:web,correlation_id:01GM3GFCYFJD458FZZ4RPPY46N,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_policy_preloader.rb:13:in `execute'*/
   app/models/preloaders/project_policy_preloader.rb:13:in `execute'
  Group Load (0.4ms)  SELECT "namespaces"."id", "namespaces"."name", "namespaces"."path", "namespaces"."owner_id", "namespaces"."created_at", "namespaces"."updated_at", "namespaces"."type", "namespaces"."description", "namespaces"."avatar", "namespaces"."membership_lock", "namespaces"."share_with_group_lock", "namespaces"."visibility_level", "namespaces"."request_access_enabled", "namespaces"."ldap_sync_status", "namespaces"."ldap_sync_error", "namespaces"."ldap_sync_last_update_at", "namespaces"."ldap_sync_last_successful_update_at", "namespaces"."ldap_sync_last_sync_at", "namespaces"."description_html", "namespaces"."lfs_enabled", "namespaces"."parent_id", "namespaces"."shared_runners_minutes_limit", "namespaces"."repository_size_limit", "namespaces"."require_two_factor_authentication", "namespaces"."two_factor_grace_period", "namespaces"."cached_markdown_version", "namespaces"."project_creation_level", "namespaces"."runners_token", "namespaces"."file_template_project_id", "namespaces"."saml_discovery_token", "namespaces"."runners_token_encrypted", "namespaces"."custom_project_templates_group_id", "namespaces"."auto_devops_enabled", "namespaces"."extra_shared_runners_minutes_limit", "namespaces"."last_ci_minutes_notification_at", "namespaces"."last_ci_minutes_usage_notification_level", "namespaces"."subgroup_creation_level", "namespaces"."emails_disabled", "namespaces"."max_pages_size", "namespaces"."max_artifacts_size", "namespaces"."mentions_disabled", "namespaces"."default_branch_protection", "namespaces"."unlock_membership_to_ldap", "namespaces"."max_personal_access_token_lifetime", "namespaces"."push_rule_id", "namespaces"."shared_runners_enabled", "namespaces"."allow_descendants_override_disabled_shared_runners", "namespaces"."traversal_ids" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" IN (22, 80) /*application:web,correlation_id:01GM3GFCYFJD458FZZ4RPPY46N,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_policy_preloader.rb:13:in `execute'*/
  ↳ app/models/preloaders/project_policy_preloader.rb:13:in `execute'

  Route Load (0.3ms)  SELECT "routes".* FROM "routes" WHERE "routes"."source_type" = 'Namespace' AND "routes"."source_id" IN (22, 80) /*application:web,correlation_id:01GM3GFCYFJD458FZZ4RPPY46N,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_policy_preloader.rb:13:in `execute'*/
   app/models/preloaders/project_policy_preloader.rb:13:in `execute'
  Namespace Load (0.8ms)  SELECT "namespaces"."id", "namespaces"."name", "namespaces"."path", "namespaces"."owner_id", "namespaces"."created_at", "namespaces"."updated_at", "namespaces"."type", "namespaces"."description", "namespaces"."avatar", "namespaces"."membership_lock", "namespaces"."share_with_group_lock", "namespaces"."visibility_level", "namespaces"."request_access_enabled", "namespaces"."ldap_sync_status", "namespaces"."ldap_sync_error", "namespaces"."ldap_sync_last_update_at", "namespaces"."ldap_sync_last_successful_update_at", "namespaces"."ldap_sync_last_sync_at", "namespaces"."description_html", "namespaces"."lfs_enabled", "namespaces"."parent_id", "namespaces"."shared_runners_minutes_limit", "namespaces"."repository_size_limit", "namespaces"."require_two_factor_authentication", "namespaces"."two_factor_grace_period", "namespaces"."cached_markdown_version", "namespaces"."project_creation_level", "namespaces"."runners_token", "namespaces"."file_template_project_id", "namespaces"."saml_discovery_token", "namespaces"."runners_token_encrypted", "namespaces"."custom_project_templates_group_id", "namespaces"."auto_devops_enabled", "namespaces"."extra_shared_runners_minutes_limit", "namespaces"."last_ci_minutes_notification_at", "namespaces"."last_ci_minutes_usage_notification_level", "namespaces"."subgroup_creation_level", "namespaces"."emails_disabled", "namespaces"."max_pages_size", "namespaces"."max_artifacts_size", "namespaces"."mentions_disabled", "namespaces"."default_branch_protection", "namespaces"."unlock_membership_to_ldap", "namespaces"."max_personal_access_token_lifetime", "namespaces"."push_rule_id", "namespaces"."shared_runners_enabled", "namespaces"."allow_descendants_override_disabled_shared_runners", "namespaces"."traversal_ids" FROM "namespaces" WHERE "namespaces"."id" IN (22, 80) /*application:web,correlation_id:01GM3GFCYFJD458FZZ4RPPY46N,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_policy_preloader.rb:13:in `execute'*/
  ↳ app/models/preloaders/project_policy_preloader.rb:13:in `execute'
  CACHE Route Load (0.0ms)  SELECT "routes".* FROM "routes" WHERE "routes"."source_type" = 'Namespace' AND "routes"."source_id" IN (22, 80)
   app/models/preloaders/project_policy_preloader.rb:13:in `execute'
  Project Load (0.9ms)  SELECT "projects".*, "project_authorizations"."user_id", "project_authorizations"."access_level" FROM "projects" LEFT OUTER JOIN "project_authorizations" AS project_authorizations ON "project_authorizations"."project_id" = "projects"."id" AND "project_authorizations"."user_id" = 1 WHERE "projects"."id" IN (20, 23) /*application:web,correlation_id:01GM3GFCYFJD458FZZ4RPPY46N,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/user_max_access_level_in_projects_preloader.rb:34:in `execute'*/
  ↳ app/models/preloaders/user_max_access_level_in_projects_preloader.rb:34:in `execute'
  Namespace Load (0.9ms)  SELECT namespaces.*, root_query.id as source_id FROM "namespaces" INNER JOIN (SELECT projects.id, namespaces.traversal_ids[1] as root_id FROM "projects" INNER JOIN "namespaces" ON "namespaces"."type" = 'Group' AND "namespaces"."id" = "projects"."namespace_id" AND "namespaces"."type" = 'Group' WHERE "projects"."id" IN (20, 23)) as root_query ON root_query.root_id = namespaces.id /*application:web,correlation_id:01GM3GFCYFJD458FZZ4RPPY46N,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_root_ancestor_preloader.rb:20:in `group_by'*/
  ↳ app/models/preloaders/project_root_ancestor_preloader.rb:20:in `group_by'
  IpRestriction Load (0.2ms)  SELECT "ip_restrictions".* FROM "ip_restrictions" WHERE "ip_restrictions"."group_id" IN (22, 79) /*application:web,correlation_id:01GM3GFCYFJD458FZZ4RPPY46N,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_root_ancestor_preloader.rb:20:in `group_by'*/
  ↳ app/models/preloaders/project_root_ancestor_preloader.rb:20:in `group_by'
  SamlProvider Load (0.6ms)  SELECT "saml_providers".* FROM "saml_providers" WHERE "saml_providers"."group_id" IN (22, 79) /*application:web,correlation_id:01GM3GFCYFJD458FZZ4RPPY46N,endpoint_id:GraphqlController#execute,db_config_name:main,line:/app/models/preloaders/project_root_ancestor_preloader.rb:20:in `group_by'*/
  ↳ app/models/preloaders/project_root_ancestor_preloader.rb:20:in `group_by'
Completed 200 OK in 86ms (Views: 0.2ms | ActiveRecord: 6.3ms | Elasticsearch: 0.0ms | Allocations: 82375)
Edited by Pedro Pombeiro

Merge request reports

Loading