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.
This commit is contained in:
Eugen Rochko 2018-10-11 00:50:18 +02:00 committed by GitHub
parent ac7df62a04
commit 790d3bc637
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 50 additions and 31 deletions

View File

@ -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 = {}
process_status_params
process_tags
ApplicationRecord.transaction do ApplicationRecord.transaction do
@status = Status.create!(status_params) @status = Status.create!(@params)
attach_tags(@status)
process_tags(@status)
end end
resolve_thread(@status) resolve_thread(@status)
@ -42,62 +46,77 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
end end
def process_status_params def process_status_params
{ @params = begin
uri: @object['id'], {
url: object_url || @object['id'], uri: @object['id'],
account: @account, url: object_url || @object['id'],
text: text_from_content || '', account: @account,
language: detected_language, text: text_from_content || '',
spoiler_text: text_from_summary || '', language: detected_language,
created_at: @object['published'], spoiler_text: text_from_summary || '',
override_timestamps: @options[:override_timestamps], created_at: @object['published'],
reply: @object['inReplyTo'].present?, override_timestamps: @options[:override_timestamps],
sensitive: @object['sensitive'] || false, reply: @object['inReplyTo'].present?,
visibility: visibility_from_audience, sensitive: @object['sensitive'] || false,
thread: replied_to_status, visibility: visibility_from_audience,
conversation: conversation_from_uri(@object['conversation']), thread: replied_to_status,
media_attachment_ids: process_attachments.take(4).map(&:id), conversation: conversation_from_uri(@object['conversation']),
} media_attachment_ids: process_attachments.take(4).map(&:id),
}
end
end end
def process_tags(status) 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
@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?