Consider using fine-grained mutation for work item notifications todos and emojis
Although it's preferred to use a single mutation for updating all widgets (see #407174 (comment 1379455011)), there are a few concerns regarding widgets that are not direct attributes of the work item like notifications, emojis and todos.
- These are typically updated in an isolated query without updating other WI properties, so the performance impact might not be justified (see previous description below for performance details).
- Permissions mismatch: this mutation uses
update_work_item
permissions (Reporter+) while these individual widgets (award_emoji
,update_subscription
,create_todo
) require guest access. -
WorkItems::UpdateService
updates theupdated_by
andupdated_at
timestamps (re: #407174 (comment 1399079576))
Proposals
- To address performance: Move these into callback classes, then we can have a fine grained service that will trigger only a particular callback class (re #407174 (comment 1379455011))
previous description
The request can be slow when using `workItemUpdate` mutation to update the user subscription on a work item, probably due to a large number of allocations inWorkItems::UpdateService
When using more fine-grained mutation (see code example below) we can observe a faster request with fewer allocations:
workItemUpdate mutation
mutation {
workItemUpdate(input: {id: "gid://gitlab/WorkItem/1667", notificationsWidget: {subscribed: true}}) {
workItem {
id
widgets{
... on WorkItemWidgetNotifications {
subscribed
}
}
}
}
}
# cold
Completed 200 OK in 1514ms (Views: 0.2ms | ActiveRecord: 72.6ms | Elasticsearch: 0.0ms | Allocations: 2049835)
# warm
Completed 200 OK in 273ms (Views: 0.2ms | ActiveRecord: 14.6ms | Elasticsearch: 0.0ms | Allocations: 308144)
workItemsSetSubscription mutation
mutation {
workItemsSetSubscription(input: { id: "gid://gitlab/WorkItem/1", subscribed: true }) {
errors
workItem {
widgets {
... on WorkItemWidgetNotifications {
subscribed
}
}
}
}
}
Completed 200 OK in 76ms (Views: 0.1ms | ActiveRecord: 6.5ms | Elasticsearch: 0.0ms | Allocations: 89238)
example granular mutation
# app/graphql/mutations/work_items/notifications/set_subscription.rb
# frozen_string_literal: true
module Mutations
module WorkItems
module Notifications
class SetSubscription < BaseMutation
graphql_name 'WorkItemsSetSubscription'
description "Subscribe to the work item notifications"
authorize :update_subscription
argument :id, ::Types::GlobalIDType[::WorkItem],
required: true,
description: 'Global ID of the work item.'
argument :subscribed,
GraphQL::Types::Boolean,
required: true,
description: 'Desired state of the subscription.'
field :work_item, Types::WorkItemType,
null: true,
description: 'Updated work item.'
def resolve(attributes)
work_item = authorized_find!(id: attributes[:id])
work_item.set_subscription(current_user, attributes[:subscribed], work_item.project)
{
work_item: work_item,
errors: errors_on_object(work_item)
}
end
def find_object(id:)
GitlabSchema.find_by_gid(id)
end
end
end
end
end
Edited by Eugenia Grieff