Class: Stalin::Adapter::Rack

Inherits:
Object
  • Object
show all
Defined in:
lib/stalin/adapter/rack.rb

Overview

Abstract base class for server-specific Rack middlewares. there is an app server that uses a signalling strategy not explicitly supported by Stalin.

Direct Known Subclasses

Puma, Unicorn

Constant Summary collapse

MB =

Conversion constant for human-readable memory amounts in log messages.

Float(1024**2)

Instance Method Summary collapse

Constructor Details

#initialize(app, graceful, abrupt, min, max, cycle, verbose) ⇒ Rack

Create a middleware instance.

Parameters:

  • app (#call)

    inner Rack application

  • graceful (Symbol)

    name of graceful-shutdown signal

  • abrupt (Symbol)

    name of abrupt-shutdown signal

  • min (Integer)

    lower-bound worker memory consumption before restart

  • max (Integer)

    upper-bound worker memory consumption before restart

  • cycle (Integer)

    how frequently to check memory consumption (# requests)

  • verbose (Boolean)

    log extra information

  • signals (Array)

    pair of two Symbol signal-names: one for “graceful shutdown please” and one for “terminate immediately”



18
19
20
21
22
23
24
25
26
27
# File 'lib/stalin/adapter/rack.rb', line 18

def initialize(app, graceful, abrupt, min, max, cycle, verbose)
  @app      = app
  @graceful = graceful
  @abrupt   = abrupt
  @min      = min
  @max      = max
  @cycle    = cycle
  @verbose  = verbose
  @req      = 0
end

Instance Method Details

#call(env) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/stalin/adapter/rack.rb', line 29

def call(env)
  result = @app.call(env)

  logger = logger_for(env)

  begin
    if @req == 0
      # First-time initialization. Deferred until first request so we can
      # ensure that init-time log output goes to the right place.
      @lim     = @min + randomize(@max - @min + 1)
      @req     = 0
      @watcher = ::Stalin::Watcher.new(Process.pid)
      @killer  = ::Stalin::Killer.new(Process.pid, @graceful, @abrupt)
      logger.info "stalin (pid: %d) startup; limit=%.1f MB, graceful=SIG%s (abrupt=SIG%s after %d tries)" %
                    [Process.pid, @lim / MB, @graceful, @abrupt, Stalin::Killer::MAX_GRACEFUL]
    end

    @req += 1

    if @req % @cycle == 0
      if (used = @watcher.watch) > @lim
        sig = @killer.kill
        logger.info "stalin (pid: %d) send SIG%s; %.1f MB > %.1f MB" %
                      [Process.pid, sig, used / MB, @lim / MB]
      elsif @verbose
        logger.info "stalin (pid: %d) soldiers on; %.1f MB < %.1f MB" %
                       [Process.pid, used / MB, @lim / MB]
      end
    end
  rescue Exception => e
    logger.error "stalin (pid: %d) ERROR %s: %s (%s)" %
                  [Process.pid, e.class.name, e.message, e.backtrace.first]
  end

  result
end