Avoid race condition when streaming deleted statuses (#10280)
* Avoid race condition when streaming deleted statuses * Move redis lock to DistributionWorker to avoid extra Redis value
This commit is contained in:
		
					parent
					
						
							
								db06b25376
							
						
					
				
			
			
				commit
				
					
						6b0eda14a1
					
				
			
		
					 2 changed files with 26 additions and 10 deletions
				
			
		|  | @ -14,6 +14,8 @@ class RemoveStatusService < BaseService | ||||||
|     @stream_entry = status.stream_entry |     @stream_entry = status.stream_entry | ||||||
|     @options      = options |     @options      = options | ||||||
| 
 | 
 | ||||||
|  |     RedisLock.acquire(lock_options) do |lock| | ||||||
|  |       if lock.acquired? | ||||||
|         remove_from_self if status.account.local? |         remove_from_self if status.account.local? | ||||||
|         remove_from_followers |         remove_from_followers | ||||||
|         remove_from_lists |         remove_from_lists | ||||||
|  | @ -24,6 +26,10 @@ class RemoveStatusService < BaseService | ||||||
|         remove_from_media if status.media_attachments.any? |         remove_from_media if status.media_attachments.any? | ||||||
| 
 | 
 | ||||||
|         @status.destroy! |         @status.destroy! | ||||||
|  |       else | ||||||
|  |         raise Mastodon::RaceConditionError | ||||||
|  |       end | ||||||
|  |     end | ||||||
| 
 | 
 | ||||||
|     # There is no reason to send out Undo activities when the |     # There is no reason to send out Undo activities when the | ||||||
|     # cause is that the original object has been removed, since |     # cause is that the original object has been removed, since | ||||||
|  | @ -156,4 +162,8 @@ class RemoveStatusService < BaseService | ||||||
|     redis.publish('timeline:public:media', @payload) |     redis.publish('timeline:public:media', @payload) | ||||||
|     redis.publish('timeline:public:local:media', @payload) if @status.local? |     redis.publish('timeline:public:local:media', @payload) if @status.local? | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   def lock_options | ||||||
|  |     { redis: Redis.current, key: "distribute:#{@status.id}" } | ||||||
|  |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -4,7 +4,13 @@ class DistributionWorker | ||||||
|   include Sidekiq::Worker |   include Sidekiq::Worker | ||||||
| 
 | 
 | ||||||
|   def perform(status_id) |   def perform(status_id) | ||||||
|  |     RedisLock.acquire(redis: Redis.current, key: "distribute:#{status_id}") do |lock| | ||||||
|  |       if lock.acquired? | ||||||
|         FanOutOnWriteService.new.call(Status.find(status_id)) |         FanOutOnWriteService.new.call(Status.find(status_id)) | ||||||
|  |       else | ||||||
|  |         raise Mastodon::RaceConditionError | ||||||
|  |       end | ||||||
|  |     end | ||||||
|   rescue ActiveRecord::RecordNotFound |   rescue ActiveRecord::RecordNotFound | ||||||
|     true |     true | ||||||
|   end |   end | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue