zbatery.git  about / heads / tags
Zbatery HTTP server for Rack
blob 53cf5edcfd5c67249d6c0cce0c2a85ea06a36c95 3472 bytes (raw)
$ git show HEAD: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
126
127
128
129
130
131
132
 
# -*- encoding: binary -*-
# :enddoc:
require 'rainbows'
Rainbows.forked = true
module Zbatery

  VERSION = "4.2.0"

  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
  @readers = [] # rainbows 4.6.x compatibility

  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
      at_exit { unlink_pid_safe(pid) if pid }
      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 } }
      trap(:CHLD, "DEFAULT")

      # 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
        begin
          ready_pipe.syswrite($$.to_s)
        rescue => e
          logger.warn("grandparent died too soon?: #{e.message} (#{e.class})")
        end
        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!
      graceful ? exit : exit!(0)
    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