Browse Source

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.
pull/4/head
Eugen Rochko 5 years ago
committed by GitHub
parent
commit
790d3bc637
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 52 additions and 33 deletions
  1. +52
    -33
      app/lib/activitypub/activity/create.rb

+ 52
- 33
app/lib/activitypub/activity/create.rb 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 = {}
ApplicationRecord.transaction do
@status = Status.create!(status_params)
process_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,62 +46,77 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
end end
def process_status_params 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),
}
end
def process_tags(status)
@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 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
TrendingTags.record_use!(hashtag, status.account, status.created_at) if status.public_visibility?
@tags << hashtag
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