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 0167397218
commit ce087ef889

View file

@ -22,12 +22,16 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
private
def process_status
status_params = process_status_params
@tags = []
@mentions = []
@params = {}
process_status_params
process_tags
ApplicationRecord.transaction do
@status = Status.create!(status_params)
process_tags(@status)
@status = Status.create!(@params)
attach_tags(@status)
end
resolve_thread(@status)
@ -42,62 +46,77 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
end
def process_status_params
{
uri: @object['id'],
url: object_url || @object['id'],
account: @account,
text: text_from_content || '',
language: detected_language,
spoiler_text: text_from_summary || '',
created_at: @object['published'],
override_timestamps: @options[:override_timestamps],
reply: @object['inReplyTo'].present?,
sensitive: @object['sensitive'] || false,
visibility: visibility_from_audience,
thread: replied_to_status,
conversation: conversation_from_uri(@object['conversation']),
media_attachment_ids: process_attachments.take(4).map(&:id),
}
@params = begin
{
uri: @object['id'],
url: object_url || @object['id'],
account: @account,
text: text_from_content || '',
language: detected_language,
spoiler_text: text_from_summary || '',
created_at: @object['published'],
override_timestamps: @options[:override_timestamps],
reply: @object['inReplyTo'].present?,
sensitive: @object['sensitive'] || false,
visibility: visibility_from_audience,
thread: replied_to_status,
conversation: conversation_from_uri(@object['conversation']),
media_attachment_ids: process_attachments.take(4).map(&:id),
}
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?
as_array(@object['tag']).each do |tag|
if equals_or_includes?(tag['type'], 'Hashtag')
process_hashtag tag, status
process_hashtag tag
elsif equals_or_includes?(tag['type'], 'Mention')
process_mention tag, status
process_mention tag
elsif equals_or_includes?(tag['type'], 'Emoji')
process_emoji tag, status
process_emoji tag
end
end
end
def process_hashtag(tag, status)
def process_hashtag(tag)
return if tag['name'].blank?
hashtag = tag['name'].gsub(/\A#/, '').mb_chars.downcase
hashtag = Tag.where(name: hashtag).first_or_create(name: hashtag)
return if status.tags.include?(hashtag)
return if @tags.include?(hashtag)
status.tags << hashtag
TrendingTags.record_use!(hashtag, status.account, status.created_at) if status.public_visibility?
@tags << hashtag
rescue ActiveRecord::RecordInvalid
nil
end
def process_mention(tag, status)
def process_mention(tag)
return if tag['href'].blank?
account = account_from_uri(tag['href'])
account = ::FetchRemoteAccountService.new.call(tag['href'], id: false) if account.nil?
return if account.nil?
account.mentions.create(status: status)
@mentions << Mention.new(account: account)
end
def process_emoji(tag, _status)
def process_emoji(tag)
return if skip_download?
return if tag['name'].blank? || tag['icon'].blank? || tag['icon']['url'].blank?