class Rack::Downtime

For the full documentation see README.md

Constants

CONTENT_LENGTH
CONTENT_TYPE

Newer versions of Rack should have these

DEFAULT_INSERT_AT
DOWNTIME_DISABLE
DOWNTIME_INSERT
ENV_KEY
VERSION

Attributes

strategy[W]

Public Class Methods

new(app, options = {}) click to toggle source

Create an instance of the Rack middleware to manage downtime notifications

Arguments

options (Hash)

downtime detection and insertion options; optional

Options

:strategy (Symbol|Hash)

Set the downtime detection strategy; defaults to Rack::Downtime::strategy. If a Hash its first value is passed as an argument to the strategy class.

:insert (String)

Path to an ERB template to insert when downtime is planned. Downtimes are given to the template as start_time and end_time.

:insert_at (String)

Where to insert the ERB template given by :insert. Can be given as a CSS selector or an XPath location.

Errors

ArgumentError

If the strategy is unknown

# File lib/rack/downtime.rb, line 51
def initialize(app, options = {})
  @app = app

  @strategy = options[:strategy] || self.class.strategy
  @strategy = load_strategy(@strategy) unless @strategy.respond_to?(:call)

  @insert = options[:insert]
  @insert = load_template(@insert) if @insert

  @insert_at = options[:insert_at] || DEFAULT_INSERT_AT
end
strategy() click to toggle source

Set the default downtime strategy

# File lib/rack/downtime.rb, line 29
def strategy
  @strategy ||= :file
end

Public Instance Methods

call(env) click to toggle source
# File lib/rack/downtime.rb, line 63
def call(env)
  return @app.call(env) if env[DOWNTIME_DISABLE] == "1"

  downtime = get_downtime(env)
  env[ENV_KEY] = downtime if downtime

  response = @app.call(env)
  return response unless downtime && insert_downtime?(env, response)

  old_body = response[2]
  new_body = insert_downtime(old_body, downtime)

  old_body.close if old_body.respond_to?(:close)
  response[1][CONTENT_LENGTH] = Rack::Utils.bytesize(new_body).to_s
  response[2] = [new_body]

  response
end

Private Instance Methods

get_downtime(env) click to toggle source
# File lib/rack/downtime.rb, line 111
def get_downtime(env)
  @strategy.call(env)
rescue => e
  message = "Rack::Downtime failed: #{e}"

  if env["rack.logger"].respond_to?(:error)
    env["rack.logger"].error(message)
  else
    env["rack.errors"].puts(message)
  end

  nil
end
insert_downtime(old_body, times) click to toggle source
# File lib/rack/downtime.rb, line 129
def insert_downtime(old_body, times)
  new_body = ""
  old_body.each { |line| new_body << line }

  doc = Nokogiri::HTML(new_body)
  e = doc.at(@insert_at)
  return new_body unless e

  message = @insert.render(*times)

  if e.child
    e.child.before(message)
  else
    e.add_child(message)
  end

  doc.to_html
end
insert_downtime?(env, response) click to toggle source
# File lib/rack/downtime.rb, line 125
def insert_downtime?(env, response)
  @insert && env[DOWNTIME_INSERT] != "0" && response[0] == 200 && response[1][CONTENT_TYPE] =~ /html/
end
load_strategy(options) click to toggle source
# File lib/rack/downtime.rb, line 84
def load_strategy(options)
  config = nil
  strategy = options
  strategy, config = strategy.first if strategy.is_a?(Hash)

  case strategy
  when :cookie
    Strategy::Cookie.new(config)
  when :env, :environment
    Strategy::Env.new(config)
  when :file
    Strategy::File.new(config)
  when :header
    Strategy::Header.new(config)
  when :query
    Strategy::Query.new(config)
  else
    raise ArgumentError, "unknown strategy: #{strategy}"
  end
end
load_template(template) click to toggle source
# File lib/rack/downtime.rb, line 105
def load_template(template)
  Class.new do
    include ERB.new(::File.read(template), nil, "<>%-").def_module("render(start_time, end_time)")
  end.new
end