Class: Puma::Reactor

Inherits:
Object
  • Object
show all
Defined in:
lib/puma/reactor.rb

Overview

Monitors a collection of IO objects, calling a block whenever any monitored object either receives data or times out, or when the Reactor shuts down.

The waiting/wake up is performed with nio4r, which will use the appropriate backend (libev, Java NIO or just plain IO#select). The call to ‘NIO::Selector#select` will ’wakeup’ any IO object that receives data.

This class additionally tracks a timeout for every added object, and wakes up any object when its timeout elapses.

The implementation uses a Queue to synchronize adding new objects from the internal select loop.

Instance Method Summary collapse

Constructor Details

#initialize(backend, &block) ⇒ Reactor

Create a new Reactor to monitor IO objects added by #add. The provided block will be invoked when an IO has data available to read, its timeout elapses, or when the Reactor shuts down.



21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/puma/reactor.rb', line 21

def initialize(backend, &block)
  require 'nio'
  valid_backends = [:auto, *::NIO::Selector.backends]
  unless valid_backends.include?(backend)
    raise ArgumentError.new("unsupported IO selector backend: #{backend} (available backends: #{valid_backends.join(', ')})")
  end

  @selector = ::NIO::Selector.new(NIO::Selector.backends.delete(backend))
  @input = Queue.new
  @timeouts = []
  @block = block
end

Instance Method Details

#add(client) ⇒ Object

Add a new client to monitor. The object must respond to #timeout and #timeout_at. Returns false if the reactor is already shut down.



49
50
51
52
53
54
55
# File 'lib/puma/reactor.rb', line 49

def add(client)
  @input << client
  @selector.wakeup
  true
rescue ClosedQueueError, IOError # Ignore if selector is already closed
  false
end

#run(background = true) ⇒ Object

Run the internal select loop, using a background thread by default.



35
36
37
38
39
40
41
42
43
44
# File 'lib/puma/reactor.rb', line 35

def run(background=true)
  if background
    @thread = Thread.new do
      Puma.set_thread_name "reactor"
      select_loop
    end
  else
    select_loop
  end
end

#shutdownObject

Shutdown the reactor, blocking until the background thread is finished.



58
59
60
61
62
63
64
65
# File 'lib/puma/reactor.rb', line 58

def shutdown
  @input.close
  begin
    @selector.wakeup
  rescue IOError # Ignore if selector is already closed
  end
  @thread&.join
end