mirror of
https://github.com/discourse/discourse.git
synced 2025-05-23 20:21:25 +08:00
SECURITY: Don't allow a particular site to monopolize the defer queue
This commit is contained in:

committed by
David Taylor

parent
0736611423
commit
26e267478d
111
lib/work_queue.rb
Normal file
111
lib/work_queue.rb
Normal file
@ -0,0 +1,111 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "monitor"
|
||||
|
||||
module WorkQueue
|
||||
class WorkQueueFull < StandardError
|
||||
end
|
||||
|
||||
class ThreadSafeWrapper
|
||||
include MonitorMixin
|
||||
|
||||
def initialize(queue)
|
||||
mon_initialize
|
||||
|
||||
@queue = queue
|
||||
@has_items = new_cond
|
||||
end
|
||||
|
||||
def push(task, force:)
|
||||
synchronize do
|
||||
previously_empty = @queue.empty?
|
||||
@queue.push(task, force: force)
|
||||
|
||||
@has_items.signal if previously_empty
|
||||
end
|
||||
end
|
||||
|
||||
def shift(block:)
|
||||
synchronize do
|
||||
loop do
|
||||
if task = @queue.shift
|
||||
break task
|
||||
elsif block
|
||||
@has_items.wait
|
||||
else
|
||||
break nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def empty?
|
||||
synchronize { @queue.empty? }
|
||||
end
|
||||
|
||||
def size
|
||||
synchronize { @queue.size }
|
||||
end
|
||||
end
|
||||
|
||||
class FairQueue
|
||||
attr_reader :size
|
||||
|
||||
def initialize(limit, &blk)
|
||||
@limit = limit
|
||||
@size = 0
|
||||
@elements = Hash.new { |h, k| h[k] = blk.call }
|
||||
end
|
||||
|
||||
def push(task, force:)
|
||||
raise WorkQueueFull if !force && @size >= @limit
|
||||
key, task = task.values_at(:key, :task)
|
||||
@elements[key].push(task, force: force)
|
||||
@size += 1
|
||||
nil
|
||||
end
|
||||
|
||||
def shift
|
||||
unless @elements.empty?
|
||||
key, queue = @elements.shift
|
||||
|
||||
task = queue.shift
|
||||
|
||||
@elements[key] = queue unless queue.empty?
|
||||
|
||||
@size -= 1
|
||||
|
||||
{ key: key, task: task }
|
||||
end
|
||||
end
|
||||
|
||||
def empty?
|
||||
@elements.empty?
|
||||
end
|
||||
end
|
||||
|
||||
class BoundedQueue
|
||||
def initialize(limit)
|
||||
@limit = limit
|
||||
@elements = []
|
||||
end
|
||||
|
||||
def push(task, force:)
|
||||
raise WorkQueueFull if !force && @elements.size >= @limit
|
||||
@elements << task
|
||||
nil
|
||||
end
|
||||
|
||||
def shift
|
||||
@elements.shift
|
||||
end
|
||||
|
||||
def empty?
|
||||
@elements.empty?
|
||||
end
|
||||
|
||||
def size
|
||||
@elements.size
|
||||
end
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user