zbatery.git  about / heads / tags
Zbatery HTTP server for Rack
blob 08ac5b18cae6bb25fafc1780e2b939de1a7559a1 3221 bytes (raw)
$ git show v4.1.1:lib/zbatery.rb	# shows this blob on the CLI

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 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
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
 
# -*- encoding: binary -*-
# :enddoc:
require 'rainbows'
Rainbows.forked = true
module Zbatery

  VERSION = "4.1.1"

  Rainbows::Const::RACK_DEFAULTS["SERVER_SOFTWARE"] = "Zbatery #{VERSION}"

  # we don't actually fork workers, but allow using the
  # {before,after}_fork hooks found in Unicorn/Rainbows!
  # config files...
  FORK_HOOK = lambda { |_,_| }
end

# :stopdoc:
# override stuff we don't need or can't use portably
module Rainbows

  module Base
    # master == worker in our case
    def init_worker_process(worker)
      after_fork.call(self, worker)
      worker.user(*user) if user.kind_of?(Array) && ! worker.switched
      build_app! unless preload_app
      Rainbows::Response.setup
      Rainbows::MaxBody.setup
      Rainbows::ProcessClient.const_set(:APP, @app)

      logger.info "Zbatery #@use worker_connections=#@worker_connections"
    end
  end

  # we can't/don't need to do the fchmod heartbeat Unicorn/Rainbows! does
  def self.tick
    alive
  end

  class HttpServer

    # only used if no concurrency model is specified
    def worker_loop(worker)
      init_worker_process(worker)
      begin
        ret = IO.select(LISTENERS, nil, nil, nil) and
        ret[0].each do |sock|
          io = sock.kgio_tryaccept and process_client(io)
        end
      rescue Errno::EINTR
      rescue Errno::EBADF, TypeError
        break
      rescue => e
        Rainbows::Error.listen_loop(e)
      end while Rainbows.alive
    end

    # no-op
    def maintain_worker_count; end
    def spawn_missing_workers; end
    def init_self_pipe!; end

    # can't just do a graceful exit if reopening logs fails, so we just
    # continue on...
    def reopen_logs
      logger.info "reopening logs"
      Unicorn::Util.reopen_logs
      logger.info "done reopening logs"
      rescue => e
        logger.error "failed reopening logs #{e.message}"
    end

    def trap_deferred(sig)
      # nothing
    end

    def join
      trap(:INT) { exit!(0) }
      trap(:TERM) { exit!(0) }
      trap(:QUIT) { Thread.new { stop } }
      trap(:USR1) { Thread.new { reopen_logs } }
      trap(:USR2) { Thread.new { reexec } }
      trap(:HUP) { Thread.new { reexec; stop } }

      # technically feasible in some cases, just not sanely supportable:
      %w(TTIN TTOU WINCH).each do |sig|
        trap(sig) do
          Thread.new { logger.info("SIG#{sig} is not handled by Zbatery") }
        end
      end

      if ready_pipe
        ready_pipe.syswrite($$.to_s)
        ready_pipe.close
        self.ready_pipe = nil
      end
      extend(Rainbows.const_get(@use))
      worker = Worker.new(0)
      before_fork.call(self, worker)
      worker_loop(worker) # runs forever
    end

    def stop(graceful = true)
      Rainbows.quit!
      exit!(0) unless graceful
    end

    def before_fork
      hook = super
      hook == Zbatery::FORK_HOOK or
        logger.warn "calling before_fork without forking"
      hook
    end

    def after_fork
      hook = super
      hook == Zbatery::FORK_HOOK or
        logger.warn "calling after_fork without having forked"
      hook
    end
  end
end

Unicorn::Configurator::DEFAULTS[:before_fork] =
  Unicorn::Configurator::DEFAULTS[:after_fork] = Zbatery::FORK_HOOK

git clone https://yhbt.net/zbatery.git