Improve performance of querying alert assignees
What does this MR do?
Querying AlertManagementAlerts with the assignee field through the GraphQL API would result in a N+1 query.
This fixes the query by using BatchLoader::Graphql to group the assignee queries at the end of the query, only once all alerts have been processed. The accomodate authorizations, this logic circumvents our GraphQL auth layer, asserting the same authorization only after the BatchLoader has completed its work.
This is currently behind a feature flag (:alert_assignee
) which simply returns an empty collection if not enabled. I'm leaving the flag in place for now.
Related issue: #219571 (closed)
Blocks: #219571 (closed)
Screenshots
GraphQL testing
Test query | Output |
---|---|
![]() |
![]() |
----- Click here for text version of relevant logs!-----
Text output:
Started POST "/api/graphql" for 24.185.40.98 at 2020-06-02 18:14:07 -0400
ApplicationSetting Load (8.5ms) SELECT "application_settings".* FROM "application_settings" ORDER BY "application_settings"."id" DESC LIMIT 1
↳ app/models/concerns/cacheable_attributes.rb:19:in `current_without_cache'
User Load (5.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
↳ ee/lib/gitlab/jira/middleware.rb:19:in `call'
Feature::FlipperFeature Load (0.9ms) SELECT "features".* FROM "features"
↳ lib/feature.rb:55:in `persisted_names'
Processing by GraphqlController#execute as */*
Parameters: {"query"=>"# Welcome to GraphiQL\n#\n# GraphiQL is an in-browser tool for writing, validating, and\n# testing GraphQL queries.\n#\n# Type queries into this side of the screen, and you will see intelligent\n# typeaheads aware of the current GraphQL type schema and live syntax and\n# validation errors highlighted within the text.\n#\n# GraphQL queries typically start with a \"{\" character. Lines that starts\n# with a # are ignored.\n#\n# An example GraphQL query might look like:\n#\n# {\n# field(arg: \"value\") {\n# subField\n# }\n# }\n#\n# Keyboard shortcuts:\n#\n# Prettify Query: Shift-Ctrl-P (or press the prettify button above)\n#\n# Run Query: Ctrl-Enter (or press the play button above)\n#\n# Auto Complete: Ctrl-Space (or just start typing)\n#\n\n\n# mutation ($projectPath: ID!, $status: AlertManagementStatus!, $iid: String!) {\n# updateAlertStatus(input: { iid: $iid, status: $status, projectPath: $projectPath }) {\n# errors\n# alert {\n# iid,\n# status\n# }\n# }\n# }\n\n\n# {\n# project(fullPath: \"root/autodevops\") {\n# \t\tid\n# fullPath\n# alertManagementAlerts(statuses: [TRIGGERED, RESOLVED]) {\n# nodes {\n# iid\n# endedAt\n# eventCount\n# monitoringTool\n# service\n# severity\n# startedAt\n# status\n# title\n# }\n# }\n# }\n# }\n\n# {\n# project(fullPath: \"root/autodevops\") {\n# \t\tid\n# fullPath\n# vulnerabilitySeveritiesCount {\n# high\n# low\n# critical\n# unknown\n# }\n# sentryErrors {\n# errors{\n# nodes {\n# id\n# sentryId\n# sentryProjectName\n# }\n \n# }\n# }\n# \t\talertManagementAlertStatusCounts {\n# acknowledged\n# triggered\n# open\n# resolved\n# all \n# \t\t}\n# }\n# }\n\n# {\n# namespace(fullPath: \"root\") {\n# \t\tprojects(includeSubgroups: true) {\n# edges {\n# node {\n# id\n# }\n# }\n# }\n# }\n# }\n\n{\n project(fullPath: \"root/autodevops\") {\n\t\tid\n fullPath\n\t\talertManagementAlerts {\n nodes {\n iid\n\t\t\t\tstatus\n\t\t\t\tassignees {\n username\n\t\t\t\t}\n }\n }\n }\n}\n\n# {\n# project(fullPath: \"root/autodevops\") {\n# \t\tid\n# fullPath\n# \t\tmergeRequests {\n# nodes {\n# iid\n# title\n# \t\t\t\tassignees {\n# nodes {\n# \t username\n# }\n# \t\t\t\t}\n# }\n# }\n# }\n# }\n\n# {\n# project(fullPath: \"root/autodevops\") {\n# \t\tid\n# fullPath\n# \t\talertManagementAlerts {\n# nodes {\n# iid\n# \t\t\t\tstatus\n# \t\t\t\tassignees {\n# username\n# \t\t\t\t}\n# notes {\n# nodes {\n# id\n# system\n# confidential\n# body\n# }\n# }\n# discussions {\n# nodes {\n# id\n# notes {\n# nodes {\n# id\n# body\n# }\n# }\n# }\n# }\n# }\n# }\n# issues {\n# nodes {\n# iid\n# description\n# notes {\n# nodes {\n# id\n# system\n# confidential\n# body\n# }\n# }\n# discussions {\n# nodes {\n# id\n# notes {\n# nodes {\n# id\n# body\n# }\n# }\n# }\n# }\n# }\n# }\n# }\n# }\n\n\n\n# mutation alertManagementSetAlertAssignees($input: SetAlertAssigneesInput!) {\n# setAlertAssignees(input: $input) {\n# errors\n# alert {\n# iid\n# status\n# title\n# assignees {\n# username\n# }\n# notes {\n# nodes {\n# author\n# system\n# body\n# }\n# }\n# }\n# }\n# }\n\n", "variables"=>"[FILTERED]", "operationName"=>nil, "graphql"=>{"query"=>"# Welcome to GraphiQL\n#\n# GraphiQL is an in-browser tool for writing, validating, and\n# testing GraphQL queries.\n#\n# Type queries into this side of the screen, and you will see intelligent\n# typeaheads aware of the current GraphQL type schema and live syntax and\n# validation errors highlighted within the text.\n#\n# GraphQL queries typically start with a \"{\" character. Lines that starts\n# with a # are ignored.\n#\n# An example GraphQL query might look like:\n#\n# {\n# field(arg: \"value\") {\n# subField\n# }\n# }\n#\n# Keyboard shortcuts:\n#\n# Prettify Query: Shift-Ctrl-P (or press the prettify button above)\n#\n# Run Query: Ctrl-Enter (or press the play button above)\n#\n# Auto Complete: Ctrl-Space (or just start typing)\n#\n\n\n# mutation ($projectPath: ID!, $status: AlertManagementStatus!, $iid: String!) {\n# updateAlertStatus(input: { iid: $iid, status: $status, projectPath: $projectPath }) {\n# errors\n# alert {\n# iid,\n# status\n# }\n# }\n# }\n\n\n# {\n# project(fullPath: \"root/autodevops\") {\n# \t\tid\n# fullPath\n# alertManagementAlerts(statuses: [TRIGGERED, RESOLVED]) {\n# nodes {\n# iid\n# endedAt\n# eventCount\n# monitoringTool\n# service\n# severity\n# startedAt\n# status\n# title\n# }\n# }\n# }\n# }\n\n# {\n# project(fullPath: \"root/autodevops\") {\n# \t\tid\n# fullPath\n# vulnerabilitySeveritiesCount {\n# high\n# low\n# critical\n# unknown\n# }\n# sentryErrors {\n# errors{\n# nodes {\n# id\n# sentryId\n# sentryProjectName\n# }\n \n# }\n# }\n# \t\talertManagementAlertStatusCounts {\n# acknowledged\n# triggered\n# open\n# resolved\n# all \n# \t\t}\n# }\n# }\n\n# {\n# namespace(fullPath: \"root\") {\n# \t\tprojects(includeSubgroups: true) {\n# edges {\n# node {\n# id\n# }\n# }\n# }\n# }\n# }\n\n{\n project(fullPath: \"root/autodevops\") {\n\t\tid\n fullPath\n\t\talertManagementAlerts {\n nodes {\n iid\n\t\t\t\tstatus\n\t\t\t\tassignees {\n username\n\t\t\t\t}\n }\n }\n }\n}\n\n# {\n# project(fullPath: \"root/autodevops\") {\n# \t\tid\n# fullPath\n# \t\tmergeRequests {\n# nodes {\n# iid\n# title\n# \t\t\t\tassignees {\n# nodes {\n# \t username\n# }\n# \t\t\t\t}\n# }\n# }\n# }\n# }\n\n# {\n# project(fullPath: \"root/autodevops\") {\n# \t\tid\n# fullPath\n# \t\talertManagementAlerts {\n# nodes {\n# iid\n# \t\t\t\tstatus\n# \t\t\t\tassignees {\n# username\n# \t\t\t\t}\n# notes {\n# nodes {\n# id\n# system\n# confidential\n# body\n# }\n# }\n# discussions {\n# nodes {\n# id\n# notes {\n# nodes {\n# id\n# body\n# }\n# }\n# }\n# }\n# }\n# }\n# issues {\n# nodes {\n# iid\n# description\n# notes {\n# nodes {\n# id\n# system\n# confidential\n# body\n# }\n# }\n# discussions {\n# nodes {\n# id\n# notes {\n# nodes {\n# id\n# body\n# }\n# }\n# }\n# }\n# }\n# }\n# }\n# }\n\n\n\n# mutation alertManagementSetAlertAssignees($input: SetAlertAssigneesInput!) {\n# setAlertAssignees(input: $input) {\n# errors\n# alert {\n# iid\n# status\n# title\n# assignees {\n# username\n# }\n# notes {\n# nodes {\n# author\n# system\n# body\n# }\n# }\n# }\n# }\n# }\n\n", "variables"=>"[FILTERED]", "operationName"=>nil}}
GeoNode Exists? (0.7ms) SELECT 1 AS one FROM "geo_nodes" LIMIT 1
↳ ee/lib/gitlab/geo.rb:36:in `block in enabled?'
SQL (5.2ms) SELECT "projects"."id" AS t0_r0, "projects"."name" AS t0_r1, "projects"."path" AS t0_r2, "projects"."description" AS t0_r3, "projects"."created_at" AS t0_r4, "projects"."updated_at" AS t0_r5, "projects"."creator_id" AS t0_r6, "projects"."namespace_id" AS t0_r7, "projects"."last_activity_at" AS t0_r8, "projects"."import_url" AS t0_r9, "projects"."visibility_level" AS t0_r10, "projects"."archived" AS t0_r11, "projects"."avatar" AS t0_r12, "projects"."merge_requests_template" AS t0_r13, "projects"."star_count" AS t0_r14, "projects"."merge_requests_rebase_enabled" AS t0_r15, "projects"."import_type" AS t0_r16, "projects"."import_source" AS t0_r17, "projects"."approvals_before_merge" AS t0_r18, "projects"."reset_approvals_on_push" AS t0_r19, "projects"."merge_requests_ff_only_enabled" AS t0_r20, "projects"."issues_template" AS t0_r21, "projects"."mirror" AS t0_r22, "projects"."mirror_last_update_at" AS t0_r23, "projects"."mirror_last_successful_update_at" AS t0_r24, "projects"."mirror_user_id" AS t0_r25, "projects"."shared_runners_enabled" AS t0_r26, "projects"."runners_token" AS t0_r27, "projects"."build_coverage_regex" AS t0_r28, "projects"."build_allow_git_fetch" AS t0_r29, "projects"."build_timeout" AS t0_r30, "projects"."mirror_trigger_builds" AS t0_r31, "projects"."pending_delete" AS t0_r32, "projects"."public_builds" AS t0_r33, "projects"."last_repository_check_failed" AS t0_r34, "projects"."last_repository_check_at" AS t0_r35, "projects"."container_registry_enabled" AS t0_r36, "projects"."only_allow_merge_if_pipeline_succeeds" AS t0_r37, "projects"."has_external_issue_tracker" AS t0_r38, "projects"."repository_storage" AS t0_r39, "projects"."repository_read_only" AS t0_r40, "projects"."request_access_enabled" AS t0_r41, "projects"."has_external_wiki" AS t0_r42, "projects"."ci_config_path" AS t0_r43, "projects"."lfs_enabled" AS t0_r44, "projects"."description_html" AS t0_r45, "projects"."only_allow_merge_if_all_discussions_are_resolved" AS t0_r46, "projects"."repository_size_limit" AS t0_r47, "projects"."printing_merge_request_link_enabled" AS t0_r48, "projects"."auto_cancel_pending_pipelines" AS t0_r49, "projects"."service_desk_enabled" AS t0_r50, "projects"."cached_markdown_version" AS t0_r51, "projects"."delete_error" AS t0_r52, "projects"."last_repository_updated_at" AS t0_r53, "projects"."disable_overriding_approvers_per_merge_request" AS t0_r54, "projects"."storage_version" AS t0_r55, "projects"."resolve_outdated_diff_discussions" AS t0_r56, "projects"."remote_mirror_available_overridden" AS t0_r57, "projects"."only_mirror_protected_branches" AS t0_r58, "projects"."pull_mirror_available_overridden" AS t0_r59, "projects"."jobs_cache_index" AS t0_r60, "projects"."external_authorization_classification_label" AS t0_r61, "projects"."mirror_overwrites_diverged_branches" AS t0_r62, "projects"."pages_https_only" AS t0_r63, "projects"."external_webhook_token" AS t0_r64, "projects"."packages_enabled" AS t0_r65, "projects"."merge_requests_author_approval" AS t0_r66, "projects"."pool_repository_id" AS t0_r67, "projects"."runners_token_encrypted" AS t0_r68, "projects"."bfg_object_map" AS t0_r69, "projects"."detected_repository_languages" AS t0_r70, "projects"."merge_requests_disable_committers_approval" AS t0_r71, "projects"."require_password_to_approve" AS t0_r72, "projects"."emails_disabled" AS t0_r73, "projects"."max_pages_size" AS t0_r74, "projects"."max_artifacts_size" AS t0_r75, "projects"."pull_mirror_branch_prefix" AS t0_r76, "projects"."remove_source_branch_after_merge" AS t0_r77, "projects"."marked_for_deletion_at" AS t0_r78, "projects"."marked_for_deletion_by_user_id" AS t0_r79, "projects"."autoclose_referenced_issues" AS t0_r80, "projects"."suggestion_commit_message" AS t0_r81, "routes"."id" AS t1_r0, "routes"."source_id" AS t1_r1, "routes"."source_type" AS t1_r2, "routes"."path" AS t1_r3, "routes"."created_at" AS t1_r4, "routes"."updated_at" AS t1_r5, "routes"."name" AS t1_r6 FROM "projects" LEFT OUTER JOIN "routes" ON "routes"."source_type" = 'Project' AND "routes"."source_id" = "projects"."id" WHERE ((LOWER(routes.path) = LOWER('root/autodevops')))
↳ app/graphql/resolvers/full_path_resolver.rb:16:in `block in model_by_full_path'
Group Load (1.7ms) SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" = 1 AND "namespaces"."type" = 'Group' LIMIT 1
↳ ee/app/policies/ee/project_policy.rb:344:in `block (2 levels) in <module:ProjectPolicy>'
AlertManagement::Alert Load (1.0ms) SELECT "alert_management_alerts".* FROM "alert_management_alerts" WHERE "alert_management_alerts"."project_id" = 21 ORDER BY "alert_management_alerts"."id" DESC LIMIT 100
↳ lib/gitlab/graphql/pagination/keyset/connection.rb:100:in `nodes'
AlertManagement::AlertAssignee Load (1.5ms) SELECT "alert_management_alert_assignees".* FROM "alert_management_alert_assignees" WHERE "alert_management_alert_assignees"."alert_id" IN (5, 4, 3, 2, 1)
↳ lib/gitlab/graphql/loaders/alert_management/alerts/assignees_loader.rb:31:in `load_assignees'
User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (12, 15)
↳ lib/gitlab/graphql/loaders/alert_management/alerts/assignees_loader.rb:31:in `load_assignees'
Completed 200 OK in 186ms (Views: 0.4ms | ActiveRecord: 17.8ms | Elasticsearch: 0.0ms | Allocations: 138881)
License Load (0.5ms) SELECT "licenses".* FROM "licenses" ORDER BY "licenses"."id" DESC LIMIT 100
↳ ee/app/models/license.rb:265:in `load_license'
Application testing
Alert list view | Log output |
---|---|
![]() |
![]() |
----- Click here for text version of relevant logs!-----
Text output:
Started POST "/api/graphql" for 24.185.40.98 at 2020-06-02 18:28:00 -0400
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
↳ ee/lib/gitlab/jira/middleware.rb:19:in `call'
Processing by Peek::ResultsController#show as JSON
Parameters: {"request_id"=>"KTB1gIQWBO3"}
Completed 200 OK in 11ms (Views: 0.1ms | ActiveRecord: 0.0ms | Elasticsearch: 0.0ms | Allocations: 21275)
License Load (0.3ms) SELECT "licenses".* FROM "licenses" ORDER BY "licenses"."id" DESC LIMIT 100
↳ ee/app/models/license.rb:265:in `load_license'
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
↳ ee/lib/gitlab/jira/middleware.rb:19:in `call'
Processing by GraphqlController#execute as */*
Parameters: {"_json"=>[{"operationName"=>"getAlerts", "variables"=>"[FILTERED]", "query"=>"query getAlerts($projectPath: ID!, $statuses: [AlertManagementStatus!], $sort: AlertManagementAlertSort, $firstPageSize: Int, $lastPageSize: Int, $prevPageCursor: String = \"\", $nextPageCursor: String = \"\") {\n project(fullPath: $projectPath) {\n alertManagementAlerts(statuses: $statuses, sort: $sort, first: $firstPageSize, last: $lastPageSize, after: $nextPageCursor, before: $prevPageCursor) {\n nodes {\n ...AlertListItem\n __typename\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n __typename\n }\n __typename\n }\n __typename\n }\n}\n\nfragment AlertListItem on AlertManagementAlert {\n iid\n title\n severity\n status\n startedAt\n endedAt\n eventCount\n issueIid\n assignees {\n username\n __typename\n }\n __typename\n}\n"}, {"operationName"=>"getAlertsCount", "variables"=>"[FILTERED]", "query"=>"query getAlertsCount($projectPath: ID!) {\n project(fullPath: $projectPath) {\n alertManagementAlertStatusCounts {\n all\n open\n acknowledged\n resolved\n triggered\n __typename\n }\n __typename\n }\n}\n"}, {"operationName"=>"getAlerts", "variables"=>"[FILTERED]", "query"=>"query getAlerts($projectPath: ID!, $statuses: [AlertManagementStatus!], $sort: AlertManagementAlertSort, $firstPageSize: Int, $lastPageSize: Int, $prevPageCursor: String = \"\", $nextPageCursor: String = \"\") {\n project(fullPath: $projectPath) {\n alertManagementAlerts(statuses: $statuses, sort: $sort, first: $firstPageSize, last: $lastPageSize, after: $nextPageCursor, before: $prevPageCursor) {\n nodes {\n ...AlertListItem\n __typename\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n __typename\n }\n __typename\n }\n __typename\n }\n}\n\nfragment AlertListItem on AlertManagementAlert {\n iid\n title\n severity\n status\n startedAt\n endedAt\n eventCount\n issueIid\n assignees {\n username\n __typename\n }\n __typename\n}\n"}], "graphql"=>{"_json"=>[{"operationName"=>"getAlerts", "variables"=>"[FILTERED]", "query"=>"query getAlerts($projectPath: ID!, $statuses: [AlertManagementStatus!], $sort: AlertManagementAlertSort, $firstPageSize: Int, $lastPageSize: Int, $prevPageCursor: String = \"\", $nextPageCursor: String = \"\") {\n project(fullPath: $projectPath) {\n alertManagementAlerts(statuses: $statuses, sort: $sort, first: $firstPageSize, last: $lastPageSize, after: $nextPageCursor, before: $prevPageCursor) {\n nodes {\n ...AlertListItem\n __typename\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n __typename\n }\n __typename\n }\n __typename\n }\n}\n\nfragment AlertListItem on AlertManagementAlert {\n iid\n title\n severity\n status\n startedAt\n endedAt\n eventCount\n issueIid\n assignees {\n username\n __typename\n }\n __typename\n}\n"}, {"operationName"=>"getAlertsCount", "variables"=>"[FILTERED]", "query"=>"query getAlertsCount($projectPath: ID!) {\n project(fullPath: $projectPath) {\n alertManagementAlertStatusCounts {\n all\n open\n acknowledged\n resolved\n triggered\n __typename\n }\n __typename\n }\n}\n"}, {"operationName"=>"getAlerts", "variables"=>"[FILTERED]", "query"=>"query getAlerts($projectPath: ID!, $statuses: [AlertManagementStatus!], $sort: AlertManagementAlertSort, $firstPageSize: Int, $lastPageSize: Int, $prevPageCursor: String = \"\", $nextPageCursor: String = \"\") {\n project(fullPath: $projectPath) {\n alertManagementAlerts(statuses: $statuses, sort: $sort, first: $firstPageSize, last: $lastPageSize, after: $nextPageCursor, before: $prevPageCursor) {\n nodes {\n ...AlertListItem\n __typename\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n __typename\n }\n __typename\n }\n __typename\n }\n}\n\nfragment AlertListItem on AlertManagementAlert {\n iid\n title\n severity\n status\n startedAt\n endedAt\n eventCount\n issueIid\n assignees {\n username\n __typename\n }\n __typename\n}\n"}]}}
SQL (2.4ms) SELECT "projects"."id" AS t0_r0, "projects"."name" AS t0_r1, "projects"."path" AS t0_r2, "projects"."description" AS t0_r3, "projects"."created_at" AS t0_r4, "projects"."updated_at" AS t0_r5, "projects"."creator_id" AS t0_r6, "projects"."namespace_id" AS t0_r7, "projects"."last_activity_at" AS t0_r8, "projects"."import_url" AS t0_r9, "projects"."visibility_level" AS t0_r10, "projects"."archived" AS t0_r11, "projects"."avatar" AS t0_r12, "projects"."merge_requests_template" AS t0_r13, "projects"."star_count" AS t0_r14, "projects"."merge_requests_rebase_enabled" AS t0_r15, "projects"."import_type" AS t0_r16, "projects"."import_source" AS t0_r17, "projects"."approvals_before_merge" AS t0_r18, "projects"."reset_approvals_on_push" AS t0_r19, "projects"."merge_requests_ff_only_enabled" AS t0_r20, "projects"."issues_template" AS t0_r21, "projects"."mirror" AS t0_r22, "projects"."mirror_last_update_at" AS t0_r23, "projects"."mirror_last_successful_update_at" AS t0_r24, "projects"."mirror_user_id" AS t0_r25, "projects"."shared_runners_enabled" AS t0_r26, "projects"."runners_token" AS t0_r27, "projects"."build_coverage_regex" AS t0_r28, "projects"."build_allow_git_fetch" AS t0_r29, "projects"."build_timeout" AS t0_r30, "projects"."mirror_trigger_builds" AS t0_r31, "projects"."pending_delete" AS t0_r32, "projects"."public_builds" AS t0_r33, "projects"."last_repository_check_failed" AS t0_r34, "projects"."last_repository_check_at" AS t0_r35, "projects"."container_registry_enabled" AS t0_r36, "projects"."only_allow_merge_if_pipeline_succeeds" AS t0_r37, "projects"."has_external_issue_tracker" AS t0_r38, "projects"."repository_storage" AS t0_r39, "projects"."repository_read_only" AS t0_r40, "projects"."request_access_enabled" AS t0_r41, "projects"."has_external_wiki" AS t0_r42, "projects"."ci_config_path" AS t0_r43, "projects"."lfs_enabled" AS t0_r44, "projects"."description_html" AS t0_r45, "projects"."only_allow_merge_if_all_discussions_are_resolved" AS t0_r46, "projects"."repository_size_limit" AS t0_r47, "projects"."printing_merge_request_link_enabled" AS t0_r48, "projects"."auto_cancel_pending_pipelines" AS t0_r49, "projects"."service_desk_enabled" AS t0_r50, "projects"."cached_markdown_version" AS t0_r51, "projects"."delete_error" AS t0_r52, "projects"."last_repository_updated_at" AS t0_r53, "projects"."disable_overriding_approvers_per_merge_request" AS t0_r54, "projects"."storage_version" AS t0_r55, "projects"."resolve_outdated_diff_discussions" AS t0_r56, "projects"."remote_mirror_available_overridden" AS t0_r57, "projects"."only_mirror_protected_branches" AS t0_r58, "projects"."pull_mirror_available_overridden" AS t0_r59, "projects"."jobs_cache_index" AS t0_r60, "projects"."external_authorization_classification_label" AS t0_r61, "projects"."mirror_overwrites_diverged_branches" AS t0_r62, "projects"."pages_https_only" AS t0_r63, "projects"."external_webhook_token" AS t0_r64, "projects"."packages_enabled" AS t0_r65, "projects"."merge_requests_author_approval" AS t0_r66, "projects"."pool_repository_id" AS t0_r67, "projects"."runners_token_encrypted" AS t0_r68, "projects"."bfg_object_map" AS t0_r69, "projects"."detected_repository_languages" AS t0_r70, "projects"."merge_requests_disable_committers_approval" AS t0_r71, "projects"."require_password_to_approve" AS t0_r72, "projects"."emails_disabled" AS t0_r73, "projects"."max_pages_size" AS t0_r74, "projects"."max_artifacts_size" AS t0_r75, "projects"."pull_mirror_branch_prefix" AS t0_r76, "projects"."remove_source_branch_after_merge" AS t0_r77, "projects"."marked_for_deletion_at" AS t0_r78, "projects"."marked_for_deletion_by_user_id" AS t0_r79, "projects"."autoclose_referenced_issues" AS t0_r80, "projects"."suggestion_commit_message" AS t0_r81, "routes"."id" AS t1_r0, "routes"."source_id" AS t1_r1, "routes"."source_type" AS t1_r2, "routes"."path" AS t1_r3, "routes"."created_at" AS t1_r4, "routes"."updated_at" AS t1_r5, "routes"."name" AS t1_r6 FROM "projects" LEFT OUTER JOIN "routes" ON "routes"."source_type" = 'Project' AND "routes"."source_id" = "projects"."id" WHERE ((LOWER(routes.path) = LOWER('root/autodevops')))
↳ app/graphql/resolvers/full_path_resolver.rb:16:in `block in model_by_full_path'
Group Load (0.5ms) SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" = 1 AND "namespaces"."type" = 'Group' LIMIT 1
↳ ee/app/policies/ee/project_policy.rb:344:in `block (2 levels) in <module:ProjectPolicy>'
AlertManagement::Alert Load (1.1ms) SELECT "alert_management_alerts".* FROM "alert_management_alerts" WHERE "alert_management_alerts"."project_id" = 21 ORDER BY "alert_management_alerts"."started_at" ASC, "alert_management_alerts"."id" DESC LIMIT 10
↳ lib/gitlab/graphql/pagination/keyset/connection.rb:100:in `nodes'
(0.4ms) SELECT COUNT(*) FROM (SELECT 1 AS one FROM "alert_management_alerts" WHERE "alert_management_alerts"."project_id" = 21 LIMIT 11) subquery_for_count
↳ lib/gitlab/graphql/pagination/keyset/connection.rb:70:in `block in has_next_page'
(0.4ms) SELECT COUNT(*) AS count_all, "alert_management_alerts"."status" AS alert_management_alerts_status FROM "alert_management_alerts" WHERE "alert_management_alerts"."project_id" = 21 GROUP BY "alert_management_alerts"."status"
↳ app/models/alert_management/alert.rb:113:in `block in <class:Alert>'
AlertManagement::Alert Load (0.4ms) SELECT "alert_management_alerts".* FROM "alert_management_alerts" WHERE "alert_management_alerts"."project_id" = 21 AND "alert_management_alerts"."status" IN (0, 1) ORDER BY "alert_management_alerts"."started_at" ASC, "alert_management_alerts"."id" DESC LIMIT 10
↳ lib/gitlab/graphql/pagination/keyset/connection.rb:100:in `nodes'
(0.4ms) SELECT COUNT(*) FROM (SELECT 1 AS one FROM "alert_management_alerts" WHERE "alert_management_alerts"."project_id" = 21 AND "alert_management_alerts"."status" IN (0, 1) LIMIT 11) subquery_for_count
↳ lib/gitlab/graphql/pagination/keyset/connection.rb:70:in `block in has_next_page'
AlertManagement::AlertAssignee Load (1.0ms) SELECT "alert_management_alert_assignees".* FROM "alert_management_alert_assignees" WHERE "alert_management_alert_assignees"."alert_id" IN (1, 2, 3, 4, 5)
↳ lib/gitlab/graphql/loaders/alert_management/alerts/assignees_loader.rb:31:in `load_assignees'
User Load (51.0ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (12, 15)
↳ lib/gitlab/graphql/loaders/alert_management/alerts/assignees_loader.rb:31:in `load_assignees'
Completed 200 OK in 421ms (Views: 1.0ms | ActiveRecord: 57.7ms | Elasticsearch: 0.0ms | Allocations: 247192)
License Load (0.8ms) SELECT "licenses".* FROM "licenses" ORDER BY "licenses"."id" DESC LIMIT 100
↳ ee/app/models/license.rb:265:in `load_license'
Does this MR meet the acceptance criteria?
Conformity
- [-] Changelog entry - feature flag!
- [-] Documentation (if required)
-
Code review guidelines -
Merge request performance guidelines -
Style guides - [-] Database guides
- [-] Separation of EE specific content
Availability and Testing
-
Review and add/update tests for this feature/bug. Consider all test levels. See the Test Planning Process. -
Tested in all supported browsers -
Informed Infrastructure department of a default or new setting change, if applicable per definition of done
Security
If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:
-
Label as security and @ mention @gitlab-com/gl-security/appsec
-
The MR includes necessary changes to maintain consistency between UI, API, email, or other methods -
Security reports checked/validated by a reviewer from the AppSec team