Class: RandomPort::Pool

Inherits:
Object
  • Object
show all
Defined in:
lib/random-port/pool.rb

Overview

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, passing FALSE.

Author

Yegor Bugayenko ([email protected])

Copyright

Copyright © 2018-2024 Yegor Bugayenko

License

MIT

Defined Under Namespace

Classes: Timeout

Constant Summary collapse

SINGLETON =

Application wide pool of ports

RandomPort::Pool.new

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sync: true, limit: 65_536) ⇒ Pool

Ctor.

Parameters:

  • sync (Boolean) (defaults to: true)

    Set it to FALSE if you want this pool to be NOT thread-safe

  • limit (Integer) (defaults to: 65_536)

    Set the maximum number of ports in the pool



58
59
60
61
62
63
64
# File 'lib/random-port/pool.rb', line 58

def initialize(sync: true, limit: 65_536)
  @ports = []
  @sync = sync
  @monitor = Monitor.new
  @limit = limit
  @next = 1024
end

Instance Attribute Details

#limitObject (readonly)

Returns the value of attribute limit.



53
54
55
# File 'lib/random-port/pool.rb', line 53

def limit
  @limit
end

Instance Method Details

#acquire(total = 1, timeout: 4) ⇒ Object

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.



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/random-port/pool.rb', line 87

def acquire(total = 1, timeout: 4)
  start = Time.now
  attempt = 0
  loop do
    if Time.now > start + timeout
      raise \
        Timeout,
        "Can't find a place in the pool of #{@limit} ports " \
        "(#{@ports.size} already occupied) " \
        "for #{total} port(s), after #{attempt} attempts in #{start.ago}"
    end
    attempt +=  1
    opts = safe { group(total) }
    if opts.nil?
      @next += 1
    else
      @next = opts.max + 1
    end
    @next = 0 if @next > 65_535
    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

#countObject Also known as: size

How many ports acquired now?



70
71
72
# File 'lib/random-port/pool.rb', line 70

def count
  @ports.count
end

#empty?Boolean

Is it empty?

Returns:

  • (Boolean)


76
77
78
# File 'lib/random-port/pool.rb', line 76

def empty?
  @ports.empty?
end

#release(port) ⇒ Object

Return it/them back to the pool.

Parameters:

  • port (Integer)

    TCP port number to release

Returns:

  • nil



120
121
122
123
124
125
126
127
128
# File 'lib/random-port/pool.rb', line 120

def release(port)
  safe do
    if port.is_a?(Array)
      port.each { |p| @ports.delete(p) }
    else
      @ports.delete(port)
    end
  end
end