Class: GemeraldBeanstalk::Server

Inherits:
Object
  • Object
show all
Defined in:
lib/gemerald_beanstalk/server.rb

Constant Summary collapse

DEFAULT_BIND_ADDRESS =

The default address to bind a server to. Matches beanstalkd.

'0.0.0.0'
DEFAULT_PORT =

The default port that a server should listen on. Matches beanstalkd.

11300
@@servers =

Index of existing servers

ThreadSafe::Cache.new

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(bind_address = nil, port = nil, start_on_init = true) ⇒ Server

Create a new GemeraldBeanstalk::Server at the given bind_address and port. start_on_init controls whether the server is immediately started or starting the server should be deferred.

Examples:

Start a new server immediately at 0.0.0.0:11300

GemeraldBeanstalk::Server.new

Create a new server at 127.0.0.1:11301 to be started later

GemeraldBeanstalk::Server.new('127.0.0.1', 11301, false)

Parameters:

  • bind_address (String) (defaults to: nil)

    IP or hostname of the host the server is bound to

  • port (Integer, String) (defaults to: nil)

    The port the server should listen on

  • start_on_init (Boolean) (defaults to: true)

    A boolean indicating whether or not the server should be started immediately or deferred.



48
49
50
51
52
53
54
# File 'lib/gemerald_beanstalk/server.rb', line 48

def initialize(bind_address = nil, port = nil, start_on_init = true)
  @bind_address = bind_address || DEFAULT_BIND_ADDRESS
  @port = port.nil? ? DEFAULT_PORT : Integer(port)
  @full_address = "#{@bind_address}:#{@port}"
  @started = false
  start if start_on_init
end

Instance Attribute Details

#beanstalkObject (readonly)

The beanstalk instance the server provides an interface for



21
22
23
# File 'lib/gemerald_beanstalk/server.rb', line 21

def beanstalk
  @beanstalk
end

#bind_addressObject (readonly)

The address or hostname of the host the server is bound to



12
13
14
# File 'lib/gemerald_beanstalk/server.rb', line 12

def bind_address
  @bind_address
end

#full_addressObject (readonly)

The bind_address and port of the server



18
19
20
# File 'lib/gemerald_beanstalk/server.rb', line 18

def full_address
  @full_address
end

#portObject (readonly)

The port the server should listen on



15
16
17
# File 'lib/gemerald_beanstalk/server.rb', line 15

def port
  @port
end

Class Method Details

.event_reactor_threadThread

Returns the thread that the EventMachine event reactor is running in.

Returns:

  • (Thread)

    the thread the event reactor is running in.



30
31
32
# File 'lib/gemerald_beanstalk/server.rb', line 30

def self.event_reactor_thread
  return @@event_reactor_thread
end

Instance Method Details

#running?Boolean

Flag indicating whether the server has been started and is currently running

Returns:

  • (Boolean)


59
60
61
# File 'lib/gemerald_beanstalk/server.rb', line 59

def running?
  return @started
end

#startGemeraldBeanstalk::Server

Adds the server to the EventMachine reactor, effectively starting the server. If the EventMachine reactor has not been started, it is started in a new thread. In the process create a new GemeraldBeanstalk::Beanstalk that the server provides the interface for. Returns after the server is open for connections.

Currently changes $PROGRAM_NAME, however this behavior is likely to change.

Returns:

Raises:

  • RuntimeError if a server is already registered at the server's full address



75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/gemerald_beanstalk/server.rb', line 75

def start
  raise RuntimeError, "Server already exists for address #{full_address}" if @@servers.put_if_absent(full_address, self)
  @beanstalk = GemeraldBeanstalk::Beanstalk.new(full_address)
  start_event_reactor
  EventMachine.run do
    @event_server = EventMachine.start_server(bind_address, port, GemeraldBeanstalk::EventServer, beanstalk)
    EventMachine.add_periodic_timer(0.01, beanstalk.method(:update_state))
  end
  $PROGRAM_NAME = "gemerald_beanstalk:#{full_address}"
  wait_for_action(:start)
  @started = true
  return self
end

#start_event_reactorObject (private)

Starts the EventMachine reactor in a new thread.



110
111
112
113
114
115
116
117
118
119
# File 'lib/gemerald_beanstalk/server.rb', line 110

def start_event_reactor
  return true if EventMachine.reactor_running?
  unless EventMachine.reactor_running?
    @@event_reactor_thread = Thread.new { EventMachine.run }
    while !EventMachine.reactor_running?
      sleep 0.1
    end
  end
  return true
end

#stopGemeraldBeanstalk::Server

Stops the server by removing it from the EventMachine reactor. Returns when the server is no longer available for connections.

Returns:

Raises:

  • RuntimeError if no server is registered at the server's full address.



95
96
97
98
99
100
101
102
103
# File 'lib/gemerald_beanstalk/server.rb', line 95

def stop
  registered_server = @@servers[full_address]
  raise "Server with address #{full_address} does not appear to have been started" unless registered_server
  EventMachine.stop_server(@event_server)
  wait_for_action(:stop)
  @@servers.delete(full_address)
  @started = false
  return self
end

#wait_for_action(action) ⇒ Object (private)

Handles waiting for a server instance to start or stop by repeatedly attempting to open TCPSocket connections.



124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/gemerald_beanstalk/server.rb', line 124

def wait_for_action(action)
  action = action.to_sym
  loop do
    begin
      TCPSocket.new(bind_address, port)
    rescue Errno::ECONNREFUSED
      next if action == :start
      break if action == :stop
    rescue Errno::ECONNRESET
      break if action == :stop
    end
    break if action == :start
  end
end