shared_connection_pool.rb 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. # frozen_string_literal: true
  2. require 'connection_pool'
  3. require_relative 'shared_timed_stack'
  4. class ConnectionPool::SharedConnectionPool < ConnectionPool
  5. def initialize(options = {}, &block)
  6. super(options, &block)
  7. @available = ConnectionPool::SharedTimedStack.new(@size, &block)
  8. end
  9. delegate :size, :flush, to: :@available
  10. def with(preferred_tag, options = {})
  11. Thread.handle_interrupt(Exception => :never) do
  12. conn = checkout(preferred_tag, options)
  13. begin
  14. Thread.handle_interrupt(Exception => :immediate) do
  15. yield conn
  16. end
  17. ensure
  18. checkin(preferred_tag)
  19. end
  20. end
  21. end
  22. def checkout(preferred_tag, options = {})
  23. if ::Thread.current[key(preferred_tag)]
  24. ::Thread.current[key_count(preferred_tag)] += 1
  25. ::Thread.current[key(preferred_tag)]
  26. else
  27. ::Thread.current[key_count(preferred_tag)] = 1
  28. ::Thread.current[key(preferred_tag)] = @available.pop(preferred_tag, options[:timeout] || @timeout)
  29. end
  30. end
  31. def checkin(preferred_tag)
  32. if preferred_tag.is_a?(Hash) && preferred_tag[:force]
  33. # ConnectionPool 2.4+ calls `checkin(force: true)` after fork.
  34. # When this happens, we should remove all connections from Thread.current
  35. ::Thread.current.keys.each do |name| # rubocop:disable Style/HashEachMethods
  36. next unless name.to_s.start_with?("#{@key}-")
  37. @available.push(::Thread.current[name])
  38. ::Thread.current[name] = nil
  39. end
  40. elsif ::Thread.current[key(preferred_tag)]
  41. if ::Thread.current[key_count(preferred_tag)] == 1
  42. @available.push(::Thread.current[key(preferred_tag)])
  43. ::Thread.current[key(preferred_tag)] = nil
  44. else
  45. ::Thread.current[key_count(preferred_tag)] -= 1
  46. end
  47. else
  48. raise ConnectionPool::Error, 'no connections are checked out'
  49. end
  50. nil
  51. end
  52. private
  53. def key(tag)
  54. :"#{@key}-#{tag}"
  55. end
  56. def key_count(tag)
  57. :"#{@key_count}-#{tag}"
  58. end
  59. end