Move network calls out of transaction in ActivityPub handler (#8951)

Mention and emoji code may perform network calls, but does not need
to do that inside the database transaction. This may improve availability
of database connections when using pgBouncer in transaction mode.
master
Eugen Rochko 6 years ago committed by GitHub
parent ac7df62a04
commit 790d3bc637
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 49
      app/lib/activitypub/activity/create.rb

@ -22,12 +22,16 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
private private
def process_status def process_status
status_params = process_status_params @tags = []
@mentions = []
@params = {}
ApplicationRecord.transaction do process_status_params
@status = Status.create!(status_params) process_tags
process_tags(@status) ApplicationRecord.transaction do
@status = Status.create!(@params)
attach_tags(@status)
end end
resolve_thread(@status) resolve_thread(@status)
@ -42,6 +46,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
end end
def process_status_params def process_status_params
@params = begin
{ {
uri: @object['id'], uri: @object['id'],
url: object_url || @object['id'], url: object_url || @object['id'],
@ -59,45 +64,59 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
media_attachment_ids: process_attachments.take(4).map(&:id), media_attachment_ids: process_attachments.take(4).map(&:id),
} }
end end
end
def attach_tags(status)
@tags.each do |tag|
status.tags << tag
TrendingTags.record_use!(hashtag, status.account, status.created_at) if status.public_visibility?
end
def process_tags(status) @mentions.each do |mention|
mention.status = status
mention.save
end
end
def process_tags
return if @object['tag'].nil? return if @object['tag'].nil?
as_array(@object['tag']).each do |tag| as_array(@object['tag']).each do |tag|
if equals_or_includes?(tag['type'], 'Hashtag') if equals_or_includes?(tag['type'], 'Hashtag')
process_hashtag tag, status process_hashtag tag
elsif equals_or_includes?(tag['type'], 'Mention') elsif equals_or_includes?(tag['type'], 'Mention')
process_mention tag, status process_mention tag
elsif equals_or_includes?(tag['type'], 'Emoji') elsif equals_or_includes?(tag['type'], 'Emoji')
process_emoji tag, status process_emoji tag
end end
end end
end end
def process_hashtag(tag, status) def process_hashtag(tag)
return if tag['name'].blank? return if tag['name'].blank?
hashtag = tag['name'].gsub(/\A#/, '').mb_chars.downcase hashtag = tag['name'].gsub(/\A#/, '').mb_chars.downcase
hashtag = Tag.where(name: hashtag).first_or_create(name: hashtag) hashtag = Tag.where(name: hashtag).first_or_create(name: hashtag)
return if status.tags.include?(hashtag) return if @tags.include?(hashtag)
status.tags << hashtag @tags << hashtag
TrendingTags.record_use!(hashtag, status.account, status.created_at) if status.public_visibility?
rescue ActiveRecord::RecordInvalid rescue ActiveRecord::RecordInvalid
nil nil
end end
def process_mention(tag, status) def process_mention(tag)
return if tag['href'].blank? return if tag['href'].blank?
account = account_from_uri(tag['href']) account = account_from_uri(tag['href'])
account = ::FetchRemoteAccountService.new.call(tag['href'], id: false) if account.nil? account = ::FetchRemoteAccountService.new.call(tag['href'], id: false) if account.nil?
return if account.nil? return if account.nil?
account.mentions.create(status: status)
@mentions << Mention.new(account: account)
end end
def process_emoji(tag, _status) def process_emoji(tag)
return if skip_download? return if skip_download?
return if tag['name'].blank? || tag['icon'].blank? || tag['icon']['url'].blank? return if tag['name'].blank? || tag['icon'].blank? || tag['icon']['url'].blank?

Loading…
Cancel
Save