From a001ddd8aa419b487adf1829e75b4a88fc474add Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Wed, 26 Aug 2026 00:19:29 -0700 Subject: [PATCH] Bound the web-push delivery queue (max_queue, not the ignored queue_size) Concurrent::ThreadPoolExecutor takes :max_queue; :queue_size was silently ignored, leaving the delivery backlog unbounded (max_queue: 0). A flood of valid push subscriptions could accumulate queued deliveries without limit -- more acute now that each delivery task also resolves DNS. Using max_queue: 10000 activates the intended cap; overflow raises RejectedExecutionError under the default :abort policy, which deliver_later already rescues (push is best-effort, retried on the next message). --- lib/web_push/pool.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/web_push/pool.rb b/lib/web_push/pool.rb index 2a0533a..d929946 100644 --- a/lib/web_push/pool.rb +++ b/lib/web_push/pool.rb @@ -3,7 +3,12 @@ class WebPush::Pool attr_reader :delivery_pool, :invalidation_pool, :connection, :invalid_subscription_handler def initialize(invalid_subscription_handler:) - @delivery_pool = Concurrent::ThreadPoolExecutor.new(max_threads: 50, queue_size: 10000) + # max_queue (not queue_size, which ThreadPoolExecutor silently ignores) caps + # the delivery backlog: an unbounded queue lets a flood of subscriptions + # accumulate without limit, more so now that each task also resolves DNS. + # Overflow raises RejectedExecutionError under the default :abort policy, + # which deliver_later rescues -- push is best-effort and retried next message. + @delivery_pool = Concurrent::ThreadPoolExecutor.new(max_threads: 50, max_queue: 10000) @invalidation_pool = Concurrent::FixedThreadPool.new(1) @connection = Net::HTTP::Persistent.new(name: "web_push", pool_size: 150) @invalid_subscription_handler = invalid_subscription_handler