Skip to content
rubencaro edited this page May 17, 2013 · 2 revisions

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.

Example: Logging the reactor latency

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

Example: Ganglia Reporting

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.