-
Notifications
You must be signed in to change notification settings - Fork 217
Plugins
Goliath plugins provide a simple mechanism to directly extend, enhance, or load your own code to run alongside Goliath within the EventMachine reactor. The plugins are run once during the initialization process, which allows them to setup their own timers, callbacks, and so forth.
If the plugin is designed to do periodic work, then remember that it will run alongside your regular request processing: plugins should be fast and simple to avoid blocking the reactor. A vanilla, bare-bones plugin is a simple Ruby file:
class MyPlugin
def initialize(address, port, config, status, logger)
# your initialization logic
end
def run
# your plugin logic
end
end
The initialize
method will receive the port of the API, the config
hash after all configuration has been loaded, the status
hash and the server logger
. The server will then execute the run
method of the plugin, which is where you can setup any timers, callbacks, etc.
Goliath ships with a simple reactor latency plugin, which simply reports the amount of time that has passed since the last report. By default, it setups a periodic (1 second) timer: if there are no long running, blocking requests, then you will see an output message in your logger every second.
module Goliath
module Plugin
class Latency
def initialize(address, port, config, status, logger)
@logger = logger
@last = Time.now.to_f
end
def run
EM.add_periodic_timer(1) do
@logger.info "LATENCY: #{Time.now.to_f - @last}"
@last = Time.now.to_f
end
end
end
end
end
Then, inside your API server you can load the plugin:
class MyServer < Goliath::API
plugin Goliath::Plugin::Latency
end
Slightly more complicated is a Ganglia reporting plugin. The purpose of this plugin is to send API status information to a Ganglia collector every 60 seconds. Hence, we want something like the following:
class Echo < Goliath::API
plugin Goliath::Plugin::Ganglia, 8000, 'events'
def response(env)
status[:ganglia][:responses] += 1
[200, {}, "Hello World"]
end
end
In the example above, we load the plugin and provide the port of our ganglia server as well as the units. Then during each request, we increment the status[:ganglia]
counter, which we then want to periodically emit to our Ganglia monitoring system:
module Goliath
module Plugin
class Ganglia
def initialize(address, port, config, status, logger)
@port = port
@status = status
@config = config
@logger = logger
@status[:ganglia] = Hash.new(0)
end
def run(port, units)
EM.add_periodic_timer(60) do
@status[:ganglia].each_pair do |key, value|
gdata = {
:name => "#{key}-#{@port}",
:units => units,
:type => 'uint32',
:value => value,
:tmax => 60,
:dmax => 60
}
if Goliath.prod?
::Ganglia::GMetric.send("ganglia.example.org", port, gdata)
else
@logger.info "Ganglia send #{gdata.inspect}"
end
@status[:ganglia][key] = 0
end
end
end
end
end
end
You can see in this example that run
takes two parameters, port
and units
, both of which are provided during plugin initialization in our API server example. The plugin creates a periodic_timer
, which every 60 seconds checks the @status
hash for new metrics, emits them to our collector, and resets the stats.
With the example above, adding new reporting metrics is as easy as incrementing a new key in the status hash. The rest is taken care of for you by the plugin.