discourse/app/jobs/regular/automatic_group_membership.rb
Alan Guo Xiang Tan 7c321d3aad
PERF: Update Group#user_count counter cache outside DB transaction (#19256)
While load testing our user creation code path in production, we
identified that executing the DB statement to update the `Group#user_count` column within a
transaction is creating a bottleneck for us. This is because the
creation of a user and addition of the user to the relevant groups are
done in a transaction. When we execute the DB statement to update
`Group#user_count` for the relevant group, a row level lock is held
until the transaction completes. This row level lock acts like a global
lock when the server is creating users that will be added to the same
group in quick succession.

Instead of updating the counter cache within a transaction which the
default ActiveRecord `counter_cache` option does, we simply update the
counter cache outside of the committing transaction.

Co-authored-by: Rafael dos Santos Silva <xfalcox@gmail.com>

Co-authored-by: Rafael dos Santos Silva <xfalcox@gmail.com>
2022-11-30 11:52:08 -03:00

27 lines
695 B
Ruby

# frozen_string_literal: true
module Jobs
class AutomaticGroupMembership < ::Jobs::Base
def execute(args)
group_id = args[:group_id]
raise Discourse::InvalidParameters.new(:group_id) if group_id.blank?
group = Group.find_by(id: group_id)
raise Discourse::InvalidParameters.new(:group_id) if group.nil?
domains = group.automatic_membership_email_domains
return if domains.blank?
Group.automatic_membership_users(domains).find_each do |user|
next unless user.email_confirmed?
group.add(user, automatic: true)
GroupActionLogger.new(Discourse.system_user, group).log_add_user_to_group(user)
end
end
end
end