class RandomPort::Pool
Pool
of TPC ports.
Use it like this:
RandomPort::Pool.new.acquire do |port| # Use the TCP port. It will be returned back # to the pool afterwards. end
You can specify the maximum amount of ports to acquire, using limit
. If more acquiring requests will arrive, an exception will be raised.
The class is thread-safe, by default. You can configure it to be not-thread-safe, using optional sync
argument of the constructor.
- Author
-
Yegor Bugayenko (yegor256@gmail.com)
- Copyright
-
Copyright © 2018 Yegor Bugayenko
- License
-
MIT
Constants
- SINGLETON
Application wide pool of ports
Attributes
limit[R]
Public Class Methods
new(sync: false, limit: 65_536)
click to toggle source
Ctor.
# File lib/random-port/pool.rb, line 54 def initialize(sync: false, limit: 65_536) @ports = [] @sync = sync @monitor = Monitor.new @limit = limit end
Public Instance Methods
acquire(total = 1, timeout: 4) { |opts| ... }
click to toggle source
Acquire a new random TCP port.
You can specify the number of ports to acquire. If it's more than one, an array will be returned.
You can specify the amount of seconds to wait until a new port is available.
# File lib/random-port/pool.rb, line 82 def acquire(total = 1, timeout: 4) start = Time.now loop do if Time.now > start + timeout raise Timeout, "Can't find a place in the pool of #{@limit} ports \ for #{total} port(s), in #{format('%.02f', Time.now - start)}s" end opts = safe do next if @ports.count + total > @limit opts = Array.new(0, total) begin (0..(total - 1)).each do |i| opts[i] = i.zero? ? take : take(opts[i - 1] + 1) end rescue Errno::EADDRINUSE, SocketError next end next if opts.any? { |p| @ports.include?(p) } d = total * (total - 1) / 2 next unless opts.inject(&:+) - total * opts.min == d @ports += opts opts end next if opts.nil? opts = opts[0] if total == 1 return opts unless block_given? begin return yield opts ensure release(opts) end end end
count()
click to toggle source
How many ports acquired now?
# File lib/random-port/pool.rb, line 65 def count @ports.count end
Also aliased as: size
empty?()
click to toggle source
Is it empty?
# File lib/random-port/pool.rb, line 71 def empty? @ports.empty? end
release(port)
click to toggle source
Return it/them back to the pool.
# File lib/random-port/pool.rb, line 117 def release(port) safe do if port.is_a?(Array) port.each { |p| @ports.delete(p) } else @ports.delete(port) end end end
Private Instance Methods
safe() { || ... }
click to toggle source
# File lib/random-port/pool.rb, line 136 def safe if @sync @monitor.synchronize { yield } else yield end end
take(opt = 0)
click to toggle source
# File lib/random-port/pool.rb, line 129 def take(opt = 0) server = TCPServer.new('127.0.0.1', opt) p = server.addr[1] server.close p end