Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package rubygem-connection_pool for 
openSUSE:Factory checked in at 2026-07-15 16:33:47
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-connection_pool (Old)
 and      /work/SRC/openSUSE:Factory/.rubygem-connection_pool.new.1991 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rubygem-connection_pool"

Wed Jul 15 16:33:47 2026 rev:3 rq:1365320 version:3.0.2

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/rubygem-connection_pool/rubygem-connection_pool.changes
  2025-02-06 22:10:53.059613688 +0100
+++ 
/work/SRC/openSUSE:Factory/.rubygem-connection_pool.new.1991/rubygem-connection_pool.changes
        2026-07-15 16:48:48.945173046 +0200
@@ -1,0 +2,6 @@
+Mon Jul 13 08:57:58 UTC 2026 - Aleksei Burlakov <[email protected]>
+
+- Update to version 3.0.2: 
+  * Support :name keyword for backwards compatibility
+
+-------------------------------------------------------------------

Old:
----
  connection_pool-2.5.0.gem

New:
----
  connection_pool-3.0.2.gem

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rubygem-connection_pool.spec ++++++
--- /var/tmp/diff_new_pack.PVBGpq/_old  2026-07-15 16:48:56.553431555 +0200
+++ /var/tmp/diff_new_pack.PVBGpq/_new  2026-07-15 16:48:56.569432099 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package rubygem-connection_pool
 #
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -24,7 +24,7 @@
 #
 
 Name:           rubygem-connection_pool
-Version:        2.5.0
+Version:        3.0.2
 Release:        0
 %define mod_name connection_pool
 %define mod_full_name %{mod_name}-%{version}

++++++ connection_pool-2.5.0.gem -> connection_pool-3.0.2.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Changes.md new/Changes.md
--- old/Changes.md      2025-01-07 21:26:26.000000000 +0100
+++ new/Changes.md      1980-01-02 01:00:00.000000000 +0100
@@ -1,5 +1,57 @@
 # connection_pool Changelog
 
+3.0.2
+------
+
+- Support :name keyword for backwards compatibility [#210]
+
+3.0.1
+------
+
+- Add missing `fork.rb` to gemspec.
+
+3.0.0
+------
+
+- **BREAKING CHANGES** `ConnectionPool` and `ConnectionPool::TimedStack` now
+  use keyword arguments rather than positional arguments everywhere. Expected 
impact is minimal as most people use the `with` API, which is unchanged.
+```ruby
+pool = ConnectionPool.new(size: 5, timeout: 5)
+pool.checkout(1) # 2.x
+pool.reap(30)    # 2.x
+pool.checkout(timeout: 1) # 3.x
+pool.reap(idle_seconds: 30) # 3.x
+```
+- Dropped support for Ruby <3.2.0
+
+2.5.5
+------
+
+- Support `ConnectionPool::TimedStack#pop(exception: false)` [#207]
+  to avoid using exceptions as control flow.
+
+2.5.4
+------
+
+- Add ability to remove a broken connection from the pool [#204, womblep]
+
+2.5.3
+------
+
+- Fix TruffleRuby/JRuby crash [#201]
+
+2.5.2
+------
+
+- Rollback inadvertant change to `auto_reload_after_fork` default. [#200]
+
+2.5.1
+------
+
+- Pass options to TimedStack in `checkout` [#195]
+- Optimize connection lookup [#196]
+- Fixes for use with Ractors
+
 2.5.0
 ------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/README.md new/README.md
--- old/README.md       2025-01-07 21:26:26.000000000 +0100
+++ new/README.md       1980-01-02 01:00:00.000000000 +0100
@@ -38,7 +38,7 @@
 $redis.then { |r| r.set 'foo' 'bar' }
 ```
 
-Optionally, you can specify a timeout override using the with-block semantics:
+Optionally, you can specify a timeout override:
 
 ``` ruby
 $memcached.with(timeout: 2.0) do |conn|
@@ -46,11 +46,9 @@
 end
 ```
 
-This will only modify the resource-get timeout for this particular
-invocation.
+This will only modify the timeout for this particular invocation.
 This is useful if you want to fail-fast on certain non-critical
 sections when a resource is not available, or conversely if you are 
comfortable blocking longer on a particular resource.
-This is not implemented in the `ConnectionPool::Wrapper` class.
 
 ## Migrating to a Connection Pool
 
@@ -72,7 +70,7 @@
 end
 ```
 
-Once you've ported your entire system to use `with`, you can simply remove 
`Wrapper` and use the simpler and faster `ConnectionPool`.
+Once you've ported your entire system to use `with`, you can remove 
`::Wrapper` and use `ConnectionPool` directly.
 
 
 ## Shutdown
@@ -90,41 +88,50 @@
 
 ## Reload
 
-You can reload a ConnectionPool instance in the case it is desired to close 
all connections to the pool and, unlike `shutdown`, afterwards recreate 
connections so the pool may continue to be used.
-Reloading may be useful after forking the process.
+You can reload a ConnectionPool instance if it is necessary to close all 
existing connections and continue to use the pool.
+ConnectionPool will automatically reload if the process is forked.
+Use `auto_reload_after_fork: false` if you don't want this behavior.
 
 ```ruby
-cp = ConnectionPool.new { Redis.new }
-cp.reload { |conn| conn.quit }
+cp = ConnectionPool.new(auto_reload_after_fork: false) { Redis.new }
+cp.reload { |conn| conn.quit } # reload manually
 cp.with { |conn| conn.get('some-count') }
 ```
 
-Like `shutdown`, this will block until all connections are checked in and 
closed.
+Like `shutdown`, `reload` will block until all connections are checked in and 
closed.
 
 ## Reap
 
-You can reap idle connections in the ConnectionPool instance to close 
connections that were created but have not been used for a certain amount of 
time. This can be useful to run periodically in a separate thread especially if 
keeping the connection open is resource intensive.
+You can call `reap` periodically on the ConnectionPool instance to close 
connections that were created but have not been used for a certain amount of 
time. This can be useful in environments where connections are expensive.
 
-You can specify how many seconds the connections have to be idle for them to 
be reaped.
-Defaults to 60 seconds.
+You can specify how many seconds the connections have to be idle for them to 
be reaped, defaulting to 60 seconds.
 
 ```ruby
 cp = ConnectionPool.new { Redis.new }
-cp.reap(300) { |conn| conn.close } # Reaps connections that have been idle for 
300 seconds (5 minutes).
+
+# Start a reaper thread to reap connections that have been
+# idle more than 300 seconds (5 minutes)
+Thread.new do
+  loop do
+    cp.reap(idle_seconds: 300, &:close)
+    sleep 30
+  end
+end
 ```
 
-### Reaper Thread
+## Discarding Connections
 
-You can start your own reaper thread to reap idle connections in the 
ConnectionPool instance on a regular interval.
+You can discard connections in the ConnectionPool instance to remove 
connections that are broken and can't be repaired. 
+It can only be done inside the block passed to `with`.
+Takes an optional block that will be executed with the connection.
 
 ```ruby
-cp = ConnectionPool.new { Redis.new }
-
-# Start a reaper thread to reap connections that have been idle for 300 
seconds (5 minutes).
-Thread.new do
-  loop do
-    cp.reap(300) { |conn| conn.close }
-    sleep 300
+pool.with do |conn|
+  begin
+    conn.execute("SELECT 1")
+  rescue SomeConnectionError
+    pool.discard_current_connection(&:close)  # remove the connection from the 
pool
+    raise
   end
 end
 ```
@@ -148,20 +155,28 @@
 cp.idle # => 1
 ```
 
-Notes
------
+## Upgrading from ConnectionPool 2
+
+* Support for Ruby <3.2 has been removed.
+* ConnectionPool's APIs now consistently use keyword arguments everywhere.
+Positional arguments must be converted to keywords:
+```ruby
+pool = ConnectionPool.new(size: 5, timeout: 5)
+pool.checkout(1) # 2.x
+pool.reap(30)    # 2.x
+pool.checkout(timeout: 1) # 3.x
+pool.reap(idle_seconds: 30) # 3.x
+```
+
+## Notes
 
 - Connections are lazily created as needed.
-- There is no provision for repairing or checking the health of a connection;
-  connections should be self-repairing. This is true of the Dalli and Redis
-  clients.
-- **WARNING**: Don't ever use `Timeout.timeout` in your Ruby code or you will 
see
+- **WARNING**: Avoid `Timeout.timeout` in your Ruby code or you can see
   occasional silent corruption and mysterious errors. The Timeout API is unsafe
-  and cannot be used correctly, ever. Use proper socket timeout options as
-  exposed by Net::HTTP, Redis, Dalli, etc.
+  and dangerous to use. Use proper socket timeout options as exposed by
+  Net::HTTP, Redis, Dalli, etc.
 
 
-Author
-------
+## Author
 
-Mike Perham, [@getajobmike](https://twitter.com/getajobmike), 
<https://www.mikeperham.com>
+Mike Perham, [@getajobmike](https://ruby.social/@getajobmike), 
<https://www.mikeperham.com>
Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/connection_pool.gemspec new/connection_pool.gemspec
--- old/connection_pool.gemspec 2025-01-07 21:26:26.000000000 +0100
+++ new/connection_pool.gemspec 1980-01-02 01:00:00.000000000 +0100
@@ -10,15 +10,26 @@
   s.description = s.summary = "Generic connection pool for Ruby"
 
   s.files = ["Changes.md", "LICENSE", "README.md", "connection_pool.gemspec",
-    "lib/connection_pool.rb", "lib/connection_pool/timed_stack.rb",
-    "lib/connection_pool/version.rb", "lib/connection_pool/wrapper.rb"]
+    "lib/connection_pool.rb",
+    "lib/connection_pool/timed_stack.rb",
+    "lib/connection_pool/version.rb",
+    "lib/connection_pool/fork.rb",
+    "lib/connection_pool/wrapper.rb"]
   s.executables = []
   s.require_paths = ["lib"]
   s.license = "MIT"
+
+  s.required_ruby_version = ">= 3.2.0"
   s.add_development_dependency "bundler"
-  s.add_development_dependency "minitest", ">= 5.0.0"
+  s.add_development_dependency "maxitest"
   s.add_development_dependency "rake"
-  s.required_ruby_version = ">= 2.5.0"
 
-  s.metadata = {"changelog_uri" => 
"https://github.com/mperham/connection_pool/blob/main/Changes.md";, 
"rubygems_mfa_required" => "true"}
+  s.metadata = {
+    "bug_tracker_uri" => "https://github.com/mperham/connection_pool/issues";,
+    "documentation_uri" => "https://github.com/mperham/connection_pool/wiki";,
+    "changelog_uri" => 
"https://github.com/mperham/connection_pool/blob/main/Changes.md";,
+    "source_code_uri" => "https://github.com/mperham/connection_pool";,
+    "homepage_uri" => "https://github.com/mperham/connection_pool";,
+    "rubygems_mfa_required" => "true"
+  }
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/connection_pool/fork.rb 
new/lib/connection_pool/fork.rb
--- old/lib/connection_pool/fork.rb     1970-01-01 01:00:00.000000000 +0100
+++ new/lib/connection_pool/fork.rb     1980-01-02 01:00:00.000000000 +0100
@@ -0,0 +1,40 @@
+class ConnectionPool
+  if Process.respond_to?(:fork)
+    INSTANCES = ObjectSpace::WeakMap.new
+    private_constant :INSTANCES
+
+    def self.after_fork
+      INSTANCES.each_value do |pool|
+        # We're in after_fork, so we know all other threads are dead.
+        # All we need to do is ensure the main thread doesn't have a
+        # checked out connection
+        pool.checkin(force: true)
+        pool.reload do |connection|
+          # Unfortunately we don't know what method to call to close the 
connection,
+          # so we try the most common one.
+          connection.close if connection.respond_to?(:close)
+        end
+      end
+      nil
+    end
+
+    module ForkTracker
+      def _fork
+        pid = super
+        if pid == 0
+          ConnectionPool.after_fork
+        end
+        pid
+      end
+    end
+    Process.singleton_class.prepend(ForkTracker)
+  else
+    # JRuby, et al
+    INSTANCES = nil
+    private_constant :INSTANCES
+
+    def self.after_fork
+      # noop
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/connection_pool/timed_stack.rb 
new/lib/connection_pool/timed_stack.rb
--- old/lib/connection_pool/timed_stack.rb      2025-01-07 21:26:26.000000000 
+0100
+++ new/lib/connection_pool/timed_stack.rb      1980-01-02 01:00:00.000000000 
+0100
@@ -1,11 +1,11 @@
 ##
 # The TimedStack manages a pool of homogeneous connections (or any resource
-# you wish to manage).  Connections are created lazily up to a given maximum
+# you wish to manage). Connections are created lazily up to a given maximum
 # number.
-
+#
 # Examples:
 #
-#    ts = TimedStack.new(1) { MyConnection.new }
+#    ts = TimedStack.new(size: 1) { MyConnection.new }
 #
 #    # fetch a connection
 #    conn = ts.pop
@@ -16,15 +16,13 @@
 #    conn = ts.pop
 #    ts.pop timeout: 5
 #    #=> raises ConnectionPool::TimeoutError after 5 seconds
-
 class ConnectionPool::TimedStack
   attr_reader :max
 
   ##
   # Creates a new pool with +size+ connections that are created from the given
   # +block+.
-
-  def initialize(size = 0, &block)
+  def initialize(size: 0, &block)
     @create_block = block
     @created = 0
     @que = []
@@ -35,16 +33,15 @@
   end
 
   ##
-  # Returns +obj+ to the stack.  +options+ is ignored in TimedStack but may be
+  # Returns +obj+ to the stack. Additional kwargs are ignored in TimedStack 
but may be
   # used by subclasses that extend TimedStack.
-
-  def push(obj, options = {})
+  def push(obj, **)
     @mutex.synchronize do
       if @shutdown_block
         @created -= 1 unless @created == 0
         @shutdown_block.call(obj)
       else
-        store_connection obj, options
+        store_connection obj, **
       end
 
       @resource.broadcast
@@ -53,29 +50,35 @@
   alias_method :<<, :push
 
   ##
-  # Retrieves a connection from the stack.  If a connection is available it is
-  # immediately returned.  If no connection is available within the given
+  # Retrieves a connection from the stack. If a connection is available it is
+  # immediately returned. If no connection is available within the given
   # timeout a ConnectionPool::TimeoutError is raised.
   #
-  # +:timeout+ is the only checked entry in +options+ and is preferred over
-  # the +timeout+ argument (which will be removed in a future release).  Other
-  # options may be used by subclasses that extend TimedStack.
-
-  def pop(timeout = 0.5, options = {})
-    options, timeout = timeout, 0.5 if Hash === timeout
-    timeout = options.fetch :timeout, timeout
-
+  # @option options [Float] :timeout (0.5) Wait this many seconds for an 
available entry
+  # @option options [Class] :exception (ConnectionPool::TimeoutError) 
Exception class to raise
+  #   if an entry was not available within the timeout period. Use `exception: 
false` to return nil.
+  #
+  # Other options may be used by subclasses that extend TimedStack.
+  def pop(timeout: 0.5, exception: ConnectionPool::TimeoutError, **)
     deadline = current_time + timeout
     @mutex.synchronize do
       loop do
         raise ConnectionPool::PoolShuttingDownError if @shutdown_block
-        return fetch_connection(options) if connection_stored?(options)
+        if (conn = try_fetch_connection(**))
+          return conn
+        end
 
-        connection = try_create(options)
+        connection = try_create(**)
         return connection if connection
 
         to_wait = deadline - current_time
-        raise ConnectionPool::TimeoutError, "Waited #{timeout} sec, 
#{length}/#{@max} available" if to_wait <= 0
+        if to_wait <= 0
+          if exception
+            raise exception, "Waited #{timeout} sec, #{length}/#{@max} 
available"
+          else
+            return nil
+          end
+        end
         @resource.wait(@mutex, to_wait)
       end
     end
@@ -86,7 +89,6 @@
   # removing it from the pool. Attempting to checkout a connection after
   # shutdown will raise +ConnectionPool::PoolShuttingDownError+ unless
   # +:reload+ is +true+.
-
   def shutdown(reload: false, &block)
     raise ArgumentError, "shutdown must receive a block" unless block
 
@@ -101,34 +103,31 @@
 
   ##
   # Reaps connections that were checked in more than +idle_seconds+ ago.
-  def reap(idle_seconds, &block)
-    raise ArgumentError, "reap must receive a block" unless block
+  def reap(idle_seconds:)
+    raise ArgumentError, "reap must receive a block" unless block_given?
     raise ArgumentError, "idle_seconds must be a number" unless 
idle_seconds.is_a?(Numeric)
     raise ConnectionPool::PoolShuttingDownError if @shutdown_block
 
-    idle.times do
-      conn =
-        @mutex.synchronize do
-          raise ConnectionPool::PoolShuttingDownError if @shutdown_block
-
-          reserve_idle_connection(idle_seconds)
-        end
+    count = idle
+    count.times do
+      conn = @mutex.synchronize do
+        raise ConnectionPool::PoolShuttingDownError if @shutdown_block
+        reserve_idle_connection(idle_seconds)
+      end
       break unless conn
 
-      block.call(conn)
+      yield conn
     end
   end
 
   ##
   # Returns +true+ if there are no available connections.
-
   def empty?
     (@created - @que.length) >= @max
   end
 
   ##
   # The number of connections available on the stack.
-
   def length
     @max - @created + @que.length
   end
@@ -139,6 +138,12 @@
     @que.length
   end
 
+  ##
+  # Reduce the created count
+  def decrement_created
+    @created -= 1 unless @created == 0
+  end
+
   private
 
   def current_time
@@ -148,9 +153,18 @@
   ##
   # This is an extension point for TimedStack and is called with a mutex.
   #
-  # This method must returns true if a connection is available on the stack.
+  # This method must returns a connection from the stack if one exists. Allows
+  # subclasses with expensive match/search algorithms to avoid double-handling
+  # their stack.
+  def try_fetch_connection(**)
+    connection_stored?(**) && fetch_connection(**)
+  end
 
-  def connection_stored?(options = nil)
+  ##
+  # This is an extension point for TimedStack and is called with a mutex.
+  #
+  # This method must returns true if a connection is available on the stack.
+  def connection_stored?(**)
     [email protected]?
   end
 
@@ -158,8 +172,7 @@
   # This is an extension point for TimedStack and is called with a mutex.
   #
   # This method must return a connection from the stack.
-
-  def fetch_connection(options = nil)
+  def fetch_connection(**)
     @que.pop&.first
   end
 
@@ -167,10 +180,8 @@
   # This is an extension point for TimedStack and is called with a mutex.
   #
   # This method must shut down all connections on the stack.
-
-  def shutdown_connections(options = nil)
-    while connection_stored?(options)
-      conn = fetch_connection(options)
+  def shutdown_connections(**)
+    while (conn = try_fetch_connection(**))
       @created -= 1 unless @created == 0
       @shutdown_block.call(conn)
     end
@@ -181,12 +192,13 @@
   #
   # This method returns the oldest idle connection if it has been idle for 
more than idle_seconds.
   # This requires that the stack is kept in order of checked in time (oldest 
first).
-
   def reserve_idle_connection(idle_seconds)
     return unless idle_connections?(idle_seconds)
 
     @created -= 1 unless @created == 0
 
+    # Most active elements are at the tail of the array.
+    # Most idle will be at the head so `shift` rather than `pop`.
     @que.shift.first
   end
 
@@ -194,17 +206,18 @@
   # This is an extension point for TimedStack and is called with a mutex.
   #
   # Returns true if the first connection in the stack has been idle for more 
than idle_seconds
-
   def idle_connections?(idle_seconds)
-    connection_stored? && (current_time - @que.first.last > idle_seconds)
+    return unless connection_stored?
+    # Most idle will be at the head so `first`
+    age = (current_time - @que.first.last)
+    age > idle_seconds
   end
 
   ##
   # This is an extension point for TimedStack and is called with a mutex.
   #
   # This method must return +obj+ to the stack.
-
-  def store_connection(obj, options = nil)
+  def store_connection(obj, **)
     @que.push [obj, current_time]
   end
 
@@ -213,8 +226,7 @@
   #
   # This method must create a connection if and only if the total number of
   # connections allowed has not been met.
-
-  def try_create(options = nil)
+  def try_create(**)
     unless @created == @max
       object = @create_block.call
       @created += 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/connection_pool/version.rb 
new/lib/connection_pool/version.rb
--- old/lib/connection_pool/version.rb  2025-01-07 21:26:26.000000000 +0100
+++ new/lib/connection_pool/version.rb  1980-01-02 01:00:00.000000000 +0100
@@ -1,3 +1,3 @@
 class ConnectionPool
-  VERSION = "2.5.0"
+  VERSION = "3.0.2"
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/connection_pool/wrapper.rb 
new/lib/connection_pool/wrapper.rb
--- old/lib/connection_pool/wrapper.rb  2025-01-07 21:26:26.000000000 +0100
+++ new/lib/connection_pool/wrapper.rb  1980-01-02 01:00:00.000000000 +0100
@@ -2,20 +2,20 @@
   class Wrapper < ::BasicObject
     METHODS = [:with, :pool_shutdown, :wrapped_pool]
 
-    def initialize(options = {}, &block)
-      @pool = options.fetch(:pool) { ::ConnectionPool.new(options, &block) }
+    def initialize(**options, &)
+      @pool = options.fetch(:pool) { ::ConnectionPool.new(**options, &) }
     end
 
     def wrapped_pool
       @pool
     end
 
-    def with(&block)
-      @pool.with(&block)
+    def with(**, &)
+      @pool.with(**, &)
     end
 
-    def pool_shutdown(&block)
-      @pool.shutdown(&block)
+    def pool_shutdown(&)
+      @pool.shutdown(&)
     end
 
     def pool_size
@@ -26,31 +26,18 @@
       @pool.available
     end
 
-    def respond_to?(id, *args)
-      METHODS.include?(id) || with { |c| c.respond_to?(id, *args) }
+    def respond_to?(id, *, **)
+      METHODS.include?(id) || with { |c| c.respond_to?(id, *, **) }
     end
 
-    # rubocop:disable Style/MissingRespondToMissing
-    if ::RUBY_VERSION >= "3.0.0"
-      def method_missing(name, *args, **kwargs, &block)
-        with do |connection|
-          connection.send(name, *args, **kwargs, &block)
-        end
-      end
-    elsif ::RUBY_VERSION >= "2.7.0"
-      ruby2_keywords def method_missing(name, *args, &block)
-        with do |connection|
-          connection.send(name, *args, &block)
-        end
-      end
-    else
-      def method_missing(name, *args, &block)
-        with do |connection|
-          connection.send(name, *args, &block)
-        end
+    def respond_to_missing?(id, *, **)
+      with { |c| c.respond_to?(id, *, **) }
+    end
+
+    def method_missing(name, *, **, &)
+      with do |connection|
+        connection.send(name, *, **, &)
       end
     end
-    # rubocop:enable Style/MethodMissingSuper
-    # rubocop:enable Style/MissingRespondToMissing
   end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/connection_pool.rb new/lib/connection_pool.rb
--- old/lib/connection_pool.rb  2025-01-07 21:26:26.000000000 +0100
+++ new/lib/connection_pool.rb  1980-01-02 01:00:00.000000000 +0100
@@ -39,72 +39,30 @@
 # - :auto_reload_after_fork - automatically drop all connections after fork, 
defaults to true
 #
 class ConnectionPool
-  DEFAULTS = {size: 5, timeout: 5, auto_reload_after_fork: true}
-
-  def self.wrap(options, &block)
-    Wrapper.new(options, &block)
-  end
-
-  if Process.respond_to?(:fork)
-    INSTANCES = ObjectSpace::WeakMap.new
-    private_constant :INSTANCES
-
-    def self.after_fork
-      INSTANCES.values.each do |pool|
-        next unless pool.auto_reload_after_fork
-
-        # We're on after fork, so we know all other threads are dead.
-        # All we need to do is to ensure the main thread doesn't have a
-        # checked out connection
-        pool.checkin(force: true)
-        pool.reload do |connection|
-          # Unfortunately we don't know what method to call to close the 
connection,
-          # so we try the most common one.
-          connection.close if connection.respond_to?(:close)
-        end
-      end
-      nil
-    end
-
-    if ::Process.respond_to?(:_fork) # MRI 3.1+
-      module ForkTracker
-        def _fork
-          pid = super
-          if pid == 0
-            ConnectionPool.after_fork
-          end
-          pid
-        end
-      end
-      Process.singleton_class.prepend(ForkTracker)
-    end
-  else
-    INSTANCES = nil
-    private_constant :INSTANCES
-
-    def self.after_fork
-      # noop
-    end
+  def self.wrap(**, &)
+    Wrapper.new(**, &)
   end
 
-  def initialize(options = {}, &block)
-    raise ArgumentError, "Connection pool requires a block" unless block
-
-    options = DEFAULTS.merge(options)
+  attr_reader :size
 
-    @size = Integer(options.fetch(:size))
-    @timeout = options.fetch(:timeout)
-    @auto_reload_after_fork = options.fetch(:auto_reload_after_fork)
+  def initialize(timeout: 5, size: 5, auto_reload_after_fork: true, name: nil, 
&)
+    raise ArgumentError, "Connection pool requires a block" unless block_given?
 
-    @available = TimedStack.new(@size, &block)
+    @size = Integer(size)
+    @timeout = Float(timeout)
+    @available = TimedStack.new(size: @size, &)
     @key = :"pool-#{@available.object_id}"
     @key_count = :"pool-#{@available.object_id}-count"
-    INSTANCES[self] = self if INSTANCES
+    @discard_key = :"pool-#{@available.object_id}-discard"
+    INSTANCES[self] = self if auto_reload_after_fork && INSTANCES
   end
 
-  def with(options = {})
+  def with(**)
+    # We need to manage exception handling manually here in order
+    # to work correctly with `Timeout.timeout` and `Thread#raise`.
+    # Otherwise an interrupted Thread can leak connections.
     Thread.handle_interrupt(Exception => :never) do
-      conn = checkout(options)
+      conn = checkout(**)
       begin
         Thread.handle_interrupt(Exception => :immediate) do
           yield conn
@@ -116,20 +74,67 @@
   end
   alias_method :then, :with
 
-  def checkout(options = {})
+  ##
+  # Marks the current thread's checked-out connection for discard.
+  #
+  # When a connection is marked for discard, it will not be returned to the 
pool
+  # when checked in. Instead, the connection will be discarded.
+  # This is useful when a connection has become invalid or corrupted
+  # and should not be reused.
+  #
+  # Takes an optional block that will be called with the connection to be 
discarded.
+  # The block should perform any necessary clean-up on the connection.
+  #
+  # @yield [conn]
+  # @yieldparam conn [Object] The connection to be discarded.
+  # @yieldreturn [void]
+  #
+  #
+  # Note: This only affects the connection currently checked out by the 
calling thread.
+  # The connection will be discarded when +checkin+ is called.
+  #
+  # @return [void]
+  #
+  # @example
+  #   pool.with do |conn|
+  #     begin
+  #       conn.execute("SELECT 1")
+  #     rescue SomeConnectionError
+  #       pool.discard_current_connection  # Mark connection as bad
+  #       raise
+  #     end
+  #   end
+  def discard_current_connection(&block)
+    ::Thread.current[@discard_key] = block || proc { |conn| conn }
+  end
+
+  def checkout(timeout: @timeout, **)
     if ::Thread.current[@key]
       ::Thread.current[@key_count] += 1
       ::Thread.current[@key]
     else
+      conn = @available.pop(timeout:, **)
+      ::Thread.current[@key] = conn
       ::Thread.current[@key_count] = 1
-      ::Thread.current[@key] = @available.pop(options[:timeout] || @timeout)
+      conn
     end
   end
 
   def checkin(force: false)
     if ::Thread.current[@key]
       if ::Thread.current[@key_count] == 1 || force
-        @available.push(::Thread.current[@key])
+        if ::Thread.current[@discard_key]
+          begin
+            @available.decrement_created
+            ::Thread.current[@discard_key].call(::Thread.current[@key])
+          rescue
+            nil
+          ensure
+            ::Thread.current[@discard_key] = nil
+          end
+        else
+          @available.push(::Thread.current[@key])
+        end
         ::Thread.current[@key] = nil
         ::Thread.current[@key_count] = nil
       else
@@ -146,31 +151,24 @@
   # Shuts down the ConnectionPool by passing each connection to +block+ and
   # then removing it from the pool. Attempting to checkout a connection after
   # shutdown will raise +ConnectionPool::PoolShuttingDownError+.
-
-  def shutdown(&block)
-    @available.shutdown(&block)
+  def shutdown(&)
+    @available.shutdown(&)
   end
 
   ##
   # Reloads the ConnectionPool by passing each connection to +block+ and then
   # removing it the pool. Subsequent checkouts will create new connections as
   # needed.
-
-  def reload(&block)
-    @available.shutdown(reload: true, &block)
+  def reload(&)
+    @available.shutdown(reload: true, &)
   end
 
   ## Reaps idle connections that have been idle for over +idle_seconds+.
   # +idle_seconds+ defaults to 60.
-  def reap(idle_seconds = 60, &block)
-    @available.reap(idle_seconds, &block)
+  def reap(idle_seconds: 60, &)
+    @available.reap(idle_seconds:, &)
   end
 
-  # Size of this connection pool
-  attr_reader :size
-  # Automatically drop all connections after fork
-  attr_reader :auto_reload_after_fork
-
   # Number of pool entries available for checkout at this instant.
   def available
     @available.length
@@ -184,3 +182,4 @@
 
 require_relative "connection_pool/timed_stack"
 require_relative "connection_pool/wrapper"
+require_relative "connection_pool/fork"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata        2025-01-07 21:26:26.000000000 +0100
+++ new/metadata        1980-01-02 01:00:00.000000000 +0100
@@ -1,15 +1,14 @@
 --- !ruby/object:Gem::Specification
 name: connection_pool
 version: !ruby/object:Gem::Version
-  version: 2.5.0
+  version: 3.0.2
 platform: ruby
 authors:
 - Mike Perham
 - Damian Janowski
-autorequire:
 bindir: bin
 cert_chain: []
-date: 2025-01-07 00:00:00.000000000 Z
+date: 1980-01-02 00:00:00.000000000 Z
 dependencies:
 - !ruby/object:Gem::Dependency
   name: bundler
@@ -26,19 +25,19 @@
       - !ruby/object:Gem::Version
         version: '0'
 - !ruby/object:Gem::Dependency
-  name: minitest
+  name: maxitest
   requirement: !ruby/object:Gem::Requirement
     requirements:
     - - ">="
       - !ruby/object:Gem::Version
-        version: 5.0.0
+        version: '0'
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
     requirements:
     - - ">="
       - !ruby/object:Gem::Version
-        version: 5.0.0
+        version: '0'
 - !ruby/object:Gem::Dependency
   name: rake
   requirement: !ruby/object:Gem::Requirement
@@ -66,6 +65,7 @@
 - README.md
 - connection_pool.gemspec
 - lib/connection_pool.rb
+- lib/connection_pool/fork.rb
 - lib/connection_pool/timed_stack.rb
 - lib/connection_pool/version.rb
 - lib/connection_pool/wrapper.rb
@@ -73,9 +73,12 @@
 licenses:
 - MIT
 metadata:
+  bug_tracker_uri: https://github.com/mperham/connection_pool/issues
+  documentation_uri: https://github.com/mperham/connection_pool/wiki
   changelog_uri: 
https://github.com/mperham/connection_pool/blob/main/Changes.md
+  source_code_uri: https://github.com/mperham/connection_pool
+  homepage_uri: https://github.com/mperham/connection_pool
   rubygems_mfa_required: 'true'
-post_install_message:
 rdoc_options: []
 require_paths:
 - lib
@@ -83,15 +86,14 @@
   requirements:
   - - ">="
     - !ruby/object:Gem::Version
-      version: 2.5.0
+      version: 3.2.0
 required_rubygems_version: !ruby/object:Gem::Requirement
   requirements:
   - - ">="
     - !ruby/object:Gem::Version
       version: '0'
 requirements: []
-rubygems_version: 3.5.22
-signing_key:
+rubygems_version: 3.6.9
 specification_version: 4
 summary: Generic connection pool for Ruby
 test_files: []

Reply via email to