about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorThibG <thib@sitedethib.com>2017-09-19 21:44:18 +0200
committerEugen Rochko <eugen@zeonfederated.com>2017-09-19 21:44:18 +0200
commit34fa305a001f18855fea2711c8d44da65b84ef24 (patch)
treed6163f0689eb70beb93dd701945f276060e54a95 /app
parentbb4d005a8381091911697175416eb9c37379155e (diff)
Fix race condition when processing incoming OStatus messages (#5013)
* Avoid races in incoming OStatus toots processing

* oops

* oops again
Diffstat (limited to 'app')
-rw-r--r--app/lib/ostatus/activity/creation.rb24
1 files changed, 18 insertions, 6 deletions
diff --git a/app/lib/ostatus/activity/creation.rb b/app/lib/ostatus/activity/creation.rb
index 4f4ef2971..2687776f9 100644
--- a/app/lib/ostatus/activity/creation.rb
+++ b/app/lib/ostatus/activity/creation.rb
@@ -14,14 +14,22 @@ class OStatus::Activity::Creation < OStatus::Activity::Base
       return result if result.first.present?
     end
 
-    Rails.logger.debug "Creating remote status #{id}"
-
-    # Return early if status already exists in db
-    status = find_status(id)
+    RedisLock.acquire(lock_options) do |lock|
+      if lock.acquired?
+        # Return early if status already exists in db
+        @status = find_status(id)
+        return [@status, false] unless @status.nil?
+        @status = process_status
+      end
+    end
 
-    return [status, false] unless status.nil?
+    [@status, true]
+  end
 
+  def process_status
+    Rails.logger.debug "Creating remote status #{id}"
     cached_reblog = reblog
+    status = nil
 
     ApplicationRecord.transaction do
       status = Status.create!(
@@ -55,7 +63,7 @@ class OStatus::Activity::Creation < OStatus::Activity::Base
     LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text?
     DistributionWorker.perform_async(status.id)
 
-    [status, true]
+    status
   end
 
   def perform_via_activitypub
@@ -179,4 +187,8 @@ class OStatus::Activity::Creation < OStatus::Activity::Base
       Account.where(uri: href).or(Account.where(url: href)).first || FetchRemoteAccountService.new.call(href)
     end
   end
+
+  def lock_options
+    { redis: Redis.current, key: "create:#{id}" }
+  end
 end