cirandas.net

ref: master

config/unicorn.conf.rb


  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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
require_relative 'dotenv'

RailsRoot = File.expand_path "#{File.dirname __FILE__}/.."
PidsDir = "#{RailsRoot}/tmp/pids"
OldPidFile = "#{PidsDir}/unicorn.pid.oldbin"

ListenAddress = "127.0.0.1"
ListenPort = 50000
UnixListen = "run/unicorn.sock"
Backlog = 2048

Workers = 5
Timeout = 60

WarmUp = true
WarmUpTime = 1
# caution use non cacheable urls
WarmUpUrl = ['/admin/plugins', '/', '/profile/content']

CurrentPrio = Process.getpriority Process::PRIO_PROCESS, 0
# put "* - nice 0" on /etc/security/limits.conf to enable
WarmUpRenice = `bash -c 'ulimit -e'`.to_i-20 >= CurrentPrio rescue false
WarmUpRenicePrio = 19

begin
  require 'unicorn/worker_killer'
  WorkerKiller = true
rescue LoadError
  WorkerKiller = nil
end
WorkerKillByRequests = 500..600
WorkerKillByMemory = 208..256

WorkerListen = true
WorkerPidFile = true

WorkerDaemons = {
  0 => {
    :name => 'delayed_job',
    :run => proc{
      Thread.new{ sleep 30.minutes; Process.kill :SIGTERM, Process.pid }
      require_relative 'dotenv'
      worker = Delayed::Worker.new
      worker.name_prefix = 'unicorn worker 0'
      worker.start
    },
  },
  1 => {
    :name => 'feed-updater',
    :run => proc{
      Thread.new{ sleep 30.minutes; Process.kill :SIGTERM, Process.pid }
      FeedUpdater.new.start
    },
  },
}

working_directory RailsRoot

worker_processes (if Workers < WorkerDaemons.count+1 then WorkerDaemons.count+1 else Workers end)
timeout Timeout

stderr_path "#{RailsRoot}/log/unicorn.stderr.log"
stdout_path "#{RailsRoot}/log/unicorn.stdout.log"
pid "#{PidsDir}/unicorn.pid"

listen "#{RailsRoot}/#{UnixListen}", :backlog => Backlog
listen "#{ListenAddress}:#{ListenPort}", :tcp_nopush => true

# combine Ruby 2 or REE with "preload_app true" for memory savings
# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
preload_app true
GC.copy_on_write_friendly = true if GC.respond_to? :copy_on_write_friendly=

# this is loaded on first run or restart conditions (URS2, HUP). Unset on first before_fork call
master_run = true

before_fork do |server, worker|
  if master_run
    if WarmUp
      Process.setpriority Process::PRIO_PROCESS, 0, WarmUpRenicePrio if WarmUpRenice

      require 'rack/test'
      client = Rack::MockRequest.new server.app
      Array(WarmUpUrl).each do |url|
        client.get url
      end

      Process.setpriority Process::PRIO_PROCESS, 0, CurrentPrio if WarmUpRenice
    end

    # Disconnect since the database connection will not carry over
    ActiveRecord::Base.connection.disconnect! if defined? ActiveRecord::Base

    if File.exists? OldPidFile
      Thread.new do
        # wait a little for the new master
        sleep WarmUpTime

        # a .oldbin file exists if unicorn was gracefully restarted with a USR2 signal
        # we should terminate the old process now that we're up and running
        old_pid = File.read(OldPidFile).to_i
        begin
          Process.kill "QUIT", old_pid
          File.delete OldPidFile
        rescue Errno::ENOENT, Errno::ESRCH
          # someone else did our job for us
        end
      end
    end

    master_run = false
  end
end

after_fork do |server, worker|
  daemon = WorkerDaemons[worker.nr]

  # Start up the database connection again in the worker
  ActiveRecord::Base.establish_connection if defined? ActiveRecord::Base

  # reset memcache connection (if using memcache-client)
  Rails.cache.instance_variable_get(:@data).reset if Rails.cache.class.to_s == 'ActiveSupport::Cache::MemCacheStore'

  if WorkerKiller
    Unicorn::WorkerKiller::MaxRequests.new nil, WorkerKillByRequests.begin, WorkerKillByRequests.end if WorkerKillByRequests
    Unicorn::WorkerKiller::Oom.new nil, WorkerKillByMemory.begin * (1024**2), WorkerKillByMemory.end * (1024**2) if WorkerKillByMemory
  end unless daemon

  # say to the kernel to kill very big workers first than other processes
  # Not very secure
  #File.open("/proc/#{Process.pid}/oom_adj", "w"){ |f| f << '12' }

  if WorkerListen
    # per-process listener ports for debugging/admin/migrations
    server.listen "#{ListenAddress}:#{ListenPort + worker.nr}", :tries => -1, :delay => 5
  end unless daemon
  if WorkerPidFile
    child_pid_file = server.config[:pid].sub '.pid', ".#{worker.nr}.pid"
    system "echo #{Process.pid} > #{child_pid_file}"
  end
end

# daemons support
require 'active_support/all'
class Unicorn::HttpServer

  def worker_loop_with_daemons worker
    daemon = WorkerDaemons[worker.nr]
    if daemon
      ctx = START_CTX.dup #save for later use with proc_name
      init_worker_process worker
      START_CTX.merge! ctx

      name = "#{worker.nr}:#{daemon[:name]}"
      proc_name "worker[#{name}]"
      @logger.info "worker=#{name} ready as a daemon"

      daemon[:run].call
    else
      worker_loop_without_daemons worker
    end
  end
  alias_method_chain :worker_loop, :daemons

  def awaken_master_with_daemons
    if SIG_QUEUE.include? :QUIT
      WORKERS.each do |pid, worker|
        daemon = WorkerDaemons[worker.nr]
        next unless daemon
        Process.kill 'TERM', pid
      end
    end
    awaken_master_without_daemons
  end
  alias_method_chain :awaken_master, :daemons

end