unicorn-rupcio 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.CHANGELOG.old +25 -0
- data/.document +28 -0
- data/.gitattributes +5 -0
- data/.gitignore +25 -0
- data/.mailmap +26 -0
- data/.manifest +144 -0
- data/.olddoc.yml +25 -0
- data/Application_Timeouts +77 -0
- data/CONTRIBUTORS +39 -0
- data/COPYING +674 -0
- data/DESIGN +99 -0
- data/Documentation/.gitignore +3 -0
- data/Documentation/unicorn.1 +222 -0
- data/Documentation/unicorn_rails.1 +207 -0
- data/FAQ +70 -0
- data/GIT-VERSION-FILE +1 -0
- data/GIT-VERSION-GEN +39 -0
- data/GNUmakefile +318 -0
- data/HACKING +117 -0
- data/ISSUES +102 -0
- data/KNOWN_ISSUES +79 -0
- data/LICENSE +67 -0
- data/Links +58 -0
- data/PHILOSOPHY +139 -0
- data/README +165 -0
- data/Rakefile +17 -0
- data/SIGNALS +123 -0
- data/Sandbox +104 -0
- data/TODO +1 -0
- data/TUNING +119 -0
- data/archive/.gitignore +3 -0
- data/archive/slrnpull.conf +4 -0
- data/bin/unicorn +129 -0
- data/bin/unicorn_rails +210 -0
- data/examples/big_app_gc.rb +3 -0
- data/examples/echo.ru +27 -0
- data/examples/init.sh +102 -0
- data/examples/logger_mp_safe.rb +26 -0
- data/examples/logrotate.conf +44 -0
- data/examples/nginx.conf +156 -0
- data/examples/unicorn.conf.minimal.rb +14 -0
- data/examples/unicorn.conf.rb +111 -0
- data/examples/unicorn.socket +11 -0
- data/examples/unicorn@.service +40 -0
- data/ext/unicorn_http/CFLAGS +13 -0
- data/ext/unicorn_http/c_util.h +115 -0
- data/ext/unicorn_http/common_field_optimization.h +128 -0
- data/ext/unicorn_http/epollexclusive.h +128 -0
- data/ext/unicorn_http/ext_help.h +38 -0
- data/ext/unicorn_http/extconf.rb +40 -0
- data/ext/unicorn_http/global_variables.h +97 -0
- data/ext/unicorn_http/httpdate.c +91 -0
- data/ext/unicorn_http/unicorn_http.c +4348 -0
- data/ext/unicorn_http/unicorn_http.rl +1054 -0
- data/ext/unicorn_http/unicorn_http_common.rl +76 -0
- data/lib/unicorn/app/old_rails/static.rb +60 -0
- data/lib/unicorn/app/old_rails.rb +36 -0
- data/lib/unicorn/cgi_wrapper.rb +148 -0
- data/lib/unicorn/configurator.rb +749 -0
- data/lib/unicorn/const.rb +22 -0
- data/lib/unicorn/http_request.rb +180 -0
- data/lib/unicorn/http_response.rb +95 -0
- data/lib/unicorn/http_server.rb +860 -0
- data/lib/unicorn/launcher.rb +63 -0
- data/lib/unicorn/oob_gc.rb +82 -0
- data/lib/unicorn/preread_input.rb +34 -0
- data/lib/unicorn/select_waiter.rb +7 -0
- data/lib/unicorn/socket_helper.rb +186 -0
- data/lib/unicorn/stream_input.rb +152 -0
- data/lib/unicorn/tee_input.rb +132 -0
- data/lib/unicorn/tmpio.rb +34 -0
- data/lib/unicorn/util.rb +91 -0
- data/lib/unicorn/version.rb +1 -0
- data/lib/unicorn/worker.rb +166 -0
- data/lib/unicorn.rb +137 -0
- data/man/man1/unicorn.1 +222 -0
- data/man/man1/unicorn_rails.1 +207 -0
- data/setup.rb +1587 -0
- data/t/.gitignore +4 -0
- data/t/GNUmakefile +5 -0
- data/t/README +49 -0
- data/t/active-unix-socket.t +110 -0
- data/t/back-out-of-upgrade.t +44 -0
- data/t/bin/unused_listen +40 -0
- data/t/client_body_buffer_size.ru +15 -0
- data/t/client_body_buffer_size.t +79 -0
- data/t/detach.ru +12 -0
- data/t/env.ru +4 -0
- data/t/fails-rack-lint.ru +6 -0
- data/t/heartbeat-timeout.ru +13 -0
- data/t/heartbeat-timeout.t +60 -0
- data/t/integration.ru +129 -0
- data/t/integration.t +509 -0
- data/t/lib.perl +309 -0
- data/t/listener_names.ru +5 -0
- data/t/my-tap-lib.sh +201 -0
- data/t/oob_gc.ru +18 -0
- data/t/oob_gc_path.ru +18 -0
- data/t/pid.ru +4 -0
- data/t/preread_input.ru +23 -0
- data/t/reload-bad-config.t +49 -0
- data/t/reopen-logs.ru +14 -0
- data/t/reopen-logs.t +36 -0
- data/t/t0010-reap-logging.sh +55 -0
- data/t/t0012-reload-empty-config.sh +86 -0
- data/t/t0013-rewindable-input-false.sh +24 -0
- data/t/t0013.ru +13 -0
- data/t/t0014-rewindable-input-true.sh +24 -0
- data/t/t0014.ru +13 -0
- data/t/t0015-configurator-internals.sh +25 -0
- data/t/t0020-at_exit-handler.sh +49 -0
- data/t/t0021-process_detach.sh +29 -0
- data/t/t0022-listener_names-preload_app.sh +32 -0
- data/t/t0300-no-default-middleware.sh +20 -0
- data/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
- data/t/t0301.ru +14 -0
- data/t/t9001-oob_gc.sh +47 -0
- data/t/t9002-oob_gc-path.sh +75 -0
- data/t/test-lib.sh +125 -0
- data/t/winch_ttin.t +64 -0
- data/t/working_directory.t +86 -0
- data/test/aggregate.rb +16 -0
- data/test/benchmark/README +60 -0
- data/test/benchmark/dd.ru +19 -0
- data/test/benchmark/ddstream.ru +51 -0
- data/test/benchmark/readinput.ru +41 -0
- data/test/benchmark/stack.ru +9 -0
- data/test/benchmark/uconnect.perl +66 -0
- data/test/exec/README +5 -0
- data/test/exec/test_exec.rb +1030 -0
- data/test/test_helper.rb +307 -0
- data/test/unit/test_configurator.rb +176 -0
- data/test/unit/test_droplet.rb +29 -0
- data/test/unit/test_http_parser.rb +885 -0
- data/test/unit/test_http_parser_ng.rb +715 -0
- data/test/unit/test_server.rb +245 -0
- data/test/unit/test_signals.rb +189 -0
- data/test/unit/test_socket_helper.rb +160 -0
- data/test/unit/test_stream_input.rb +211 -0
- data/test/unit/test_tee_input.rb +304 -0
- data/test/unit/test_util.rb +132 -0
- data/test/unit/test_waiter.rb +35 -0
- data/unicorn.gemspec +49 -0
- metadata +266 -0
data/TUNING
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
= Tuning unicorn
|
2
|
+
|
3
|
+
unicorn performance is generally as good as a (mostly) Ruby web server
|
4
|
+
can provide. Most often the performance bottleneck is in the web
|
5
|
+
application running on Unicorn rather than Unicorn itself.
|
6
|
+
|
7
|
+
== unicorn Configuration
|
8
|
+
|
9
|
+
See Unicorn::Configurator for details on the config file format.
|
10
|
+
+worker_processes+ is the most-commonly needed tuning parameter.
|
11
|
+
|
12
|
+
=== Unicorn::Configurator#worker_processes
|
13
|
+
|
14
|
+
* worker_processes should be scaled to the number of processes your
|
15
|
+
backend system(s) can support. DO NOT scale it to the number of
|
16
|
+
external network clients your application expects to be serving.
|
17
|
+
unicorn is NOT for serving slow clients, that is the job of nginx.
|
18
|
+
|
19
|
+
* worker_processes should be *at* *least* the number of CPU cores on
|
20
|
+
a dedicated server (unless you do not have enough memory).
|
21
|
+
If your application has occasionally slow responses that are /not/
|
22
|
+
CPU-intensive, you may increase this to workaround those inefficiencies.
|
23
|
+
|
24
|
+
* Under Ruby 2.2 or later, Etc.nprocessors may be used to determine
|
25
|
+
the number of CPU cores present.
|
26
|
+
|
27
|
+
* worker_processes may be increased for Unicorn::OobGC users to provide
|
28
|
+
more consistent response times.
|
29
|
+
|
30
|
+
* Never, ever, increase worker_processes to the point where the system
|
31
|
+
runs out of physical memory and hits swap. Production servers should
|
32
|
+
never see heavy swap activity.
|
33
|
+
|
34
|
+
=== Unicorn::Configurator#listen Options
|
35
|
+
|
36
|
+
* Setting a very low value for the :backlog parameter in "listen"
|
37
|
+
directives can allow failover to happen more quickly if your
|
38
|
+
cluster is configured for it.
|
39
|
+
|
40
|
+
* If you're doing extremely simple benchmarks and getting connection
|
41
|
+
errors under high request rates, increasing your :backlog parameter
|
42
|
+
above the already-generous default of 1024 can help avoid connection
|
43
|
+
errors. Keep in mind this is not recommended for real traffic if
|
44
|
+
you have another machine to failover to (see above).
|
45
|
+
|
46
|
+
* :rcvbuf and :sndbuf parameters generally do not need to be set for TCP
|
47
|
+
listeners under Linux 2.6 because auto-tuning is enabled. UNIX domain
|
48
|
+
sockets do not have auto-tuning buffer sizes; so increasing those will
|
49
|
+
allow syscalls and task switches to be saved for larger requests
|
50
|
+
and responses. If your app only generates small responses or expects
|
51
|
+
small requests, you may shrink the buffer sizes to save memory, too.
|
52
|
+
|
53
|
+
* Having socket buffers too large can also be detrimental or have
|
54
|
+
little effect. Huge buffers can put more pressure on the allocator
|
55
|
+
and may also thrash CPU caches, cancelling out performance gains
|
56
|
+
one would normally expect.
|
57
|
+
|
58
|
+
* UNIX domain sockets are slightly faster than TCP sockets, but only
|
59
|
+
work if nginx is on the same machine.
|
60
|
+
|
61
|
+
== Other unicorn settings
|
62
|
+
|
63
|
+
* Setting "preload_app true" can allow copy-on-write-friendly GC to
|
64
|
+
be used to save memory. It will probably not work out of the box with
|
65
|
+
applications that open sockets or perform random I/O on files.
|
66
|
+
Databases like TokyoCabinet use concurrency-safe pread()/pwrite()
|
67
|
+
functions for safe sharing of database file descriptors across
|
68
|
+
processes.
|
69
|
+
|
70
|
+
* On POSIX-compliant filesystems, it is safe for multiple threads or
|
71
|
+
processes to append to one log file as long as all the processes are
|
72
|
+
have them unbuffered (File#sync = true) or they are
|
73
|
+
record(line)-buffered in userspace before any writes.
|
74
|
+
|
75
|
+
== Kernel Parameters (Linux sysctl and sysfs)
|
76
|
+
|
77
|
+
WARNING: Do not change system parameters unless you know what you're doing!
|
78
|
+
|
79
|
+
* Transparent hugepages (THP) improves performance in many cases,
|
80
|
+
but can also increase memory use when relying on a
|
81
|
+
copy-on-write(CoW)-friendly GC (Ruby 2.0+) with "preload_app true".
|
82
|
+
CoW operates at the page level, so writing to a huge page would
|
83
|
+
trigger a 2 MB copy (x86-64), as opposed to a 4 KB copy on a
|
84
|
+
regular (non-huge) page.
|
85
|
+
|
86
|
+
Consider only allowing THP to be used when it is requested via the
|
87
|
+
madvise(2) syscall:
|
88
|
+
|
89
|
+
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
|
90
|
+
|
91
|
+
Or disabling it system-wide, via "never".
|
92
|
+
|
93
|
+
n.b. "page" in this context only applies to the OS kernel,
|
94
|
+
Ruby GC implementations also use this term for the same concept
|
95
|
+
in a way that is agnostic to the OS.
|
96
|
+
|
97
|
+
* net.core.rmem_max and net.core.wmem_max can increase the allowed
|
98
|
+
size of :rcvbuf and :sndbuf respectively. This is mostly only useful
|
99
|
+
for UNIX domain sockets which do not have auto-tuning buffer sizes.
|
100
|
+
|
101
|
+
* For load testing/benchmarking with UNIX domain sockets, you should
|
102
|
+
consider increasing net.core.somaxconn or else nginx will start
|
103
|
+
failing to connect under heavy load. You may also consider setting
|
104
|
+
a higher :backlog to listen on as noted earlier.
|
105
|
+
|
106
|
+
* If you're running out of local ports, consider lowering
|
107
|
+
net.ipv4.tcp_fin_timeout to 20-30 (default: 60 seconds). Also
|
108
|
+
consider widening the usable port range by changing
|
109
|
+
net.ipv4.ip_local_port_range.
|
110
|
+
|
111
|
+
* Setting net.ipv4.tcp_timestamps=1 will also allow setting
|
112
|
+
net.ipv4.tcp_tw_reuse=1 and net.ipv4.tcp_tw_recycle=1, which along
|
113
|
+
with the above settings can slow down port exhaustion. Not all
|
114
|
+
networks are compatible with these settings, check with your friendly
|
115
|
+
network administrator before changing these.
|
116
|
+
|
117
|
+
* Increasing the MTU size can reduce framing overhead for larger
|
118
|
+
transfers. One often-overlooked detail is that the loopback
|
119
|
+
device (usually "lo") can have its MTU increased, too.
|
data/archive/.gitignore
ADDED
data/bin/unicorn
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
#!/this/will/be/overwritten/or/wrapped/anyways/do/not/worry/ruby
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
# frozen_string_literal: false
|
4
|
+
require 'unicorn/launcher'
|
5
|
+
require 'optparse'
|
6
|
+
|
7
|
+
ENV["RACK_ENV"] ||= "development"
|
8
|
+
rackup_opts = Unicorn::Configurator::RACKUP
|
9
|
+
options = rackup_opts[:options]
|
10
|
+
set_no_default_middleware = true
|
11
|
+
|
12
|
+
op = OptionParser.new("", 24, ' ') do |opts|
|
13
|
+
cmd = File.basename($0)
|
14
|
+
opts.banner = "Usage: #{cmd} " \
|
15
|
+
"[ruby options] [#{cmd} options] [rackup config file]"
|
16
|
+
opts.separator "Ruby options:"
|
17
|
+
|
18
|
+
lineno = 1
|
19
|
+
opts.on("-e", "--eval LINE", "evaluate a LINE of code") do |line|
|
20
|
+
eval line, TOPLEVEL_BINDING, "-e", lineno
|
21
|
+
lineno += 1
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") do
|
25
|
+
$DEBUG = true
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on("-w", "--warn", "turn warnings on for your script") do
|
29
|
+
$-w = true
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on("-I", "--include PATH",
|
33
|
+
"specify $LOAD_PATH (may be used more than once)") do |path|
|
34
|
+
$LOAD_PATH.unshift(*path.split(':'))
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on("-r", "--require LIBRARY",
|
38
|
+
"require the library, before executing your script") do |library|
|
39
|
+
require library
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.separator "#{cmd} options:"
|
43
|
+
|
44
|
+
# some of these switches exist for rackup command-line compatibility,
|
45
|
+
|
46
|
+
opts.on("-o", "--host HOST",
|
47
|
+
"listen on HOST (default: #{Unicorn::Const::DEFAULT_HOST})") do |h|
|
48
|
+
rackup_opts[:host] = h
|
49
|
+
rackup_opts[:set_listener] = true
|
50
|
+
end
|
51
|
+
|
52
|
+
opts.on("-p", "--port PORT", Integer,
|
53
|
+
"use PORT (default: #{Unicorn::Const::DEFAULT_PORT})") do |port|
|
54
|
+
rackup_opts[:port] = port
|
55
|
+
rackup_opts[:set_listener] = true
|
56
|
+
end
|
57
|
+
|
58
|
+
opts.on("-E", "--env RACK_ENV",
|
59
|
+
"use RACK_ENV for defaults (default: development)") do |e|
|
60
|
+
ENV["RACK_ENV"] = e
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on("-N", "--no-default-middleware",
|
64
|
+
"do not load middleware implied by RACK_ENV") do |e|
|
65
|
+
rackup_opts[:no_default_middleware] = true if set_no_default_middleware
|
66
|
+
end
|
67
|
+
|
68
|
+
opts.on("-D", "--daemonize", "run daemonized in the background") do |d|
|
69
|
+
rackup_opts[:daemonize] = !!d
|
70
|
+
end
|
71
|
+
|
72
|
+
opts.on("-P", "--pid FILE", "DEPRECATED") do |f|
|
73
|
+
warn %q{Use of --pid/-P is strongly discouraged}
|
74
|
+
warn %q{Use the 'pid' directive in the Unicorn config file instead}
|
75
|
+
options[:pid] = f
|
76
|
+
end
|
77
|
+
|
78
|
+
opts.on("-s", "--server SERVER",
|
79
|
+
"this flag only exists for compatibility") do |s|
|
80
|
+
warn "-s/--server only exists for compatibility with rackup"
|
81
|
+
end
|
82
|
+
|
83
|
+
# Unicorn-specific stuff
|
84
|
+
opts.on("-l", "--listen {HOST:PORT|PATH}",
|
85
|
+
"listen on HOST:PORT or PATH",
|
86
|
+
"this may be specified multiple times",
|
87
|
+
"(default: #{Unicorn::Const::DEFAULT_LISTEN})") do |address|
|
88
|
+
options[:listeners] << address
|
89
|
+
end
|
90
|
+
|
91
|
+
opts.on("-c", "--config-file FILE", "Unicorn-specific config file") do |f|
|
92
|
+
options[:config_file] = f
|
93
|
+
end
|
94
|
+
|
95
|
+
# I'm avoiding Unicorn-specific config options on the command-line.
|
96
|
+
# IMNSHO, config options on the command-line are redundant given
|
97
|
+
# config files and make things unnecessarily complicated with multiple
|
98
|
+
# places to look for a config option.
|
99
|
+
|
100
|
+
opts.separator "Common options:"
|
101
|
+
|
102
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
103
|
+
puts opts.to_s.gsub(/^.*DEPRECATED.*$/s, '')
|
104
|
+
exit
|
105
|
+
end
|
106
|
+
|
107
|
+
opts.on_tail("-v", "--version", "Show version") do
|
108
|
+
puts "#{cmd} v#{Unicorn::Const::UNICORN_VERSION}"
|
109
|
+
exit
|
110
|
+
end
|
111
|
+
|
112
|
+
opts.parse! ARGV
|
113
|
+
end
|
114
|
+
|
115
|
+
set_no_default_middleware = false
|
116
|
+
app = Unicorn.builder(ARGV[0] || 'config.ru', op)
|
117
|
+
op = nil
|
118
|
+
|
119
|
+
if $DEBUG
|
120
|
+
require 'pp'
|
121
|
+
pp({
|
122
|
+
:unicorn_options => options,
|
123
|
+
:app => app,
|
124
|
+
:daemonize => rackup_opts[:daemonize],
|
125
|
+
})
|
126
|
+
end
|
127
|
+
|
128
|
+
Unicorn::Launcher.daemonize!(options) if rackup_opts[:daemonize]
|
129
|
+
Unicorn::HttpServer.new(app, options).start.join
|
data/bin/unicorn_rails
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
#!/this/will/be/overwritten/or/wrapped/anyways/do/not/worry/ruby
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
# frozen_string_literal: false
|
4
|
+
require 'unicorn/launcher'
|
5
|
+
require 'optparse'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
ENV['RAILS_ENV'] ||= "development"
|
9
|
+
rackup_opts = Unicorn::Configurator::RACKUP
|
10
|
+
options = rackup_opts[:options]
|
11
|
+
|
12
|
+
op = OptionParser.new("", 24, ' ') do |opts|
|
13
|
+
cmd = File.basename($0)
|
14
|
+
opts.banner = "Usage: #{cmd} " \
|
15
|
+
"[ruby options] [#{cmd} options] [rackup config file]"
|
16
|
+
opts.separator "Ruby options:"
|
17
|
+
|
18
|
+
lineno = 1
|
19
|
+
opts.on("-e", "--eval LINE", "evaluate a LINE of code") do |line|
|
20
|
+
eval line, TOPLEVEL_BINDING, "-e", lineno
|
21
|
+
lineno += 1
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") do
|
25
|
+
$DEBUG = true
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on("-w", "--warn", "turn warnings on for your script") do
|
29
|
+
$-w = true
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on("-I", "--include PATH",
|
33
|
+
"specify $LOAD_PATH (may be used more than once)") do |path|
|
34
|
+
$LOAD_PATH.unshift(*path.split(':'))
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on("-r", "--require LIBRARY",
|
38
|
+
"require the library, before executing your script") do |library|
|
39
|
+
require library
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.separator "#{cmd} options:"
|
43
|
+
|
44
|
+
# some of these switches exist for rackup command-line compatibility,
|
45
|
+
|
46
|
+
opts.on("-o", "--host HOST",
|
47
|
+
"listen on HOST (default: #{Unicorn::Const::DEFAULT_HOST})") do |h|
|
48
|
+
rackup_opts[:host] = h
|
49
|
+
rackup_opts[:set_listener] = true
|
50
|
+
end
|
51
|
+
|
52
|
+
opts.on("-p", "--port PORT", Integer,
|
53
|
+
"use PORT (default: #{Unicorn::Const::DEFAULT_PORT})") do |port|
|
54
|
+
rackup_opts[:port] = port
|
55
|
+
rackup_opts[:set_listener] = true
|
56
|
+
end
|
57
|
+
|
58
|
+
opts.on("-E", "--env RAILS_ENV",
|
59
|
+
"use RAILS_ENV for defaults (default: development)") do |e|
|
60
|
+
ENV['RAILS_ENV'] = e
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on("-D", "--daemonize", "run daemonized in the background") do |d|
|
64
|
+
rackup_opts[:daemonize] = !!d
|
65
|
+
end
|
66
|
+
|
67
|
+
# Unicorn-specific stuff
|
68
|
+
opts.on("-l", "--listen {HOST:PORT|PATH}",
|
69
|
+
"listen on HOST:PORT or PATH",
|
70
|
+
"this may be specified multiple times",
|
71
|
+
"(default: #{Unicorn::Const::DEFAULT_LISTEN})") do |address|
|
72
|
+
options[:listeners] << address
|
73
|
+
end
|
74
|
+
|
75
|
+
opts.on("-c", "--config-file FILE", "Unicorn-specific config file") do |f|
|
76
|
+
options[:config_file] = f
|
77
|
+
end
|
78
|
+
|
79
|
+
opts.on("-P PATH", "DEPRECATED") do |v|
|
80
|
+
warn %q{Use of -P is ambiguous and discouraged}
|
81
|
+
warn %q{Use --path or RAILS_RELATIVE_URL_ROOT instead}
|
82
|
+
ENV['RAILS_RELATIVE_URL_ROOT'] = v
|
83
|
+
end
|
84
|
+
|
85
|
+
opts.on("--path PATH", "Runs Rails app mounted at a specific path.",
|
86
|
+
"(default: /)") do |v|
|
87
|
+
ENV['RAILS_RELATIVE_URL_ROOT'] = v
|
88
|
+
end
|
89
|
+
|
90
|
+
# I'm avoiding Unicorn-specific config options on the command-line.
|
91
|
+
# IMNSHO, config options on the command-line are redundant given
|
92
|
+
# config files and make things unnecessarily complicated with multiple
|
93
|
+
# places to look for a config option.
|
94
|
+
|
95
|
+
opts.separator "Common options:"
|
96
|
+
|
97
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
98
|
+
puts opts.to_s.gsub(/^.*DEPRECATED.*$/s, '')
|
99
|
+
exit
|
100
|
+
end
|
101
|
+
|
102
|
+
opts.on_tail("-v", "--version", "Show version") do
|
103
|
+
puts "#{cmd} v#{Unicorn::Const::UNICORN_VERSION}"
|
104
|
+
exit
|
105
|
+
end
|
106
|
+
|
107
|
+
opts.parse! ARGV
|
108
|
+
end
|
109
|
+
|
110
|
+
def rails_dispatcher
|
111
|
+
if ::Rails::VERSION::MAJOR >= 3 && ::File.exist?('config/application.rb')
|
112
|
+
if ::File.read('config/application.rb') =~ /^module\s+([\w:]+)\s*$/
|
113
|
+
app_module = Object.const_get($1)
|
114
|
+
begin
|
115
|
+
result = app_module::Application
|
116
|
+
rescue NameError
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
if result.nil? && defined?(ActionController::Dispatcher)
|
122
|
+
result = ActionController::Dispatcher.new
|
123
|
+
end
|
124
|
+
|
125
|
+
result || abort("Unable to locate the application dispatcher class")
|
126
|
+
end
|
127
|
+
|
128
|
+
def rails_builder(ru, op, daemonize)
|
129
|
+
return Unicorn.builder(ru, op) if ru
|
130
|
+
|
131
|
+
# allow Configurator to parse cli switches embedded in the ru file
|
132
|
+
Unicorn::Configurator::RACKUP.update(:file => :rails, :optparse => op)
|
133
|
+
|
134
|
+
# this lambda won't run until after forking if preload_app is false
|
135
|
+
# this runs after config file reloading
|
136
|
+
lambda do |x, server|
|
137
|
+
# Rails 3 includes a config.ru, use it if we find it after
|
138
|
+
# working_directory is bound.
|
139
|
+
::File.exist?('config.ru') and
|
140
|
+
return Unicorn.builder('config.ru', op).call(x, server)
|
141
|
+
|
142
|
+
# Load Rails and (possibly) the private version of Rack it bundles.
|
143
|
+
begin
|
144
|
+
require ::File.expand_path('config/boot')
|
145
|
+
require ::File.expand_path('config/environment')
|
146
|
+
rescue LoadError => err
|
147
|
+
abort "#$0 must be run inside RAILS_ROOT: #{err.inspect}"
|
148
|
+
end
|
149
|
+
|
150
|
+
defined?(::Rails::VERSION::STRING) or
|
151
|
+
abort "Rails::VERSION::STRING not defined by config/{boot,environment}"
|
152
|
+
# it seems Rails >=2.2 support Rack, but only >=2.3 requires it
|
153
|
+
old_rails = case ::Rails::VERSION::MAJOR
|
154
|
+
when 0, 1 then true
|
155
|
+
when 2 then Rails::VERSION::MINOR < 3 ? true : false
|
156
|
+
else
|
157
|
+
false
|
158
|
+
end
|
159
|
+
|
160
|
+
Rack::Builder.new do
|
161
|
+
map_path = ENV['RAILS_RELATIVE_URL_ROOT'] || '/'
|
162
|
+
if old_rails
|
163
|
+
if map_path != '/'
|
164
|
+
# patches + tests welcome, but I really cbf to deal with this
|
165
|
+
# since all apps I've ever dealt with just use "/" ...
|
166
|
+
warn "relative URL roots may not work for older Rails"
|
167
|
+
end
|
168
|
+
warn "LogTailer not available for Rails < 2.3" unless daemonize
|
169
|
+
warn "Debugger not available" if $DEBUG
|
170
|
+
require 'unicorn/app/old_rails'
|
171
|
+
map(map_path) do
|
172
|
+
use Unicorn::App::OldRails::Static
|
173
|
+
run Unicorn::App::OldRails.new
|
174
|
+
end
|
175
|
+
else
|
176
|
+
use Rails::Rack::LogTailer unless daemonize
|
177
|
+
use Rails::Rack::Debugger if $DEBUG
|
178
|
+
map(map_path) do
|
179
|
+
unless defined?(ActionDispatch::Static)
|
180
|
+
use Rails::Rack::Static
|
181
|
+
end
|
182
|
+
run rails_dispatcher
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end.to_app
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
app = rails_builder(ARGV[0], op, rackup_opts[:daemonize])
|
190
|
+
op = nil
|
191
|
+
|
192
|
+
if $DEBUG
|
193
|
+
require 'pp'
|
194
|
+
pp({
|
195
|
+
:unicorn_options => options,
|
196
|
+
:app => app,
|
197
|
+
:daemonize => rackup_opts[:daemonize],
|
198
|
+
})
|
199
|
+
end
|
200
|
+
|
201
|
+
# ensure Rails standard tmp paths exist
|
202
|
+
options[:after_reload] = lambda do
|
203
|
+
FileUtils.mkdir_p(%w(cache pids sessions sockets).map! { |d| "tmp/#{d}" })
|
204
|
+
end
|
205
|
+
|
206
|
+
if rackup_opts[:daemonize]
|
207
|
+
options[:pid] = "tmp/pids/unicorn.pid"
|
208
|
+
Unicorn::Launcher.daemonize!(options)
|
209
|
+
end
|
210
|
+
Unicorn::HttpServer.new(app, options).start.join
|
data/examples/echo.ru
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#\-E none
|
2
|
+
# frozen_string_literal: false
|
3
|
+
#
|
4
|
+
# Example application that echoes read data back to the HTTP client.
|
5
|
+
# This emulates the old echo protocol people used to run.
|
6
|
+
#
|
7
|
+
# An example of using this in a client would be to run:
|
8
|
+
# curl --no-buffer -T- http://host:port/
|
9
|
+
#
|
10
|
+
# Then type random stuff in your terminal to watch it get echoed back!
|
11
|
+
|
12
|
+
class EchoBody < Struct.new(:input)
|
13
|
+
|
14
|
+
def each(&block)
|
15
|
+
while buf = input.read(4096)
|
16
|
+
yield buf
|
17
|
+
end
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
run lambda { |env|
|
24
|
+
/\A100-continue\z/i =~ env['HTTP_EXPECT'] and return [100, {}, []]
|
25
|
+
[ 200, { 'Content-Type' => 'application/octet-stream' },
|
26
|
+
EchoBody.new(env['rack.input']) ]
|
27
|
+
}
|
data/examples/init.sh
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
set -e
|
3
|
+
### BEGIN INIT INFO
|
4
|
+
# Provides: unicorn
|
5
|
+
# Required-Start: $local_fs $network
|
6
|
+
# Required-Stop: $local_fs $network
|
7
|
+
# Default-Start: 2 3 4 5
|
8
|
+
# Default-Stop: 0 1 6
|
9
|
+
# Short-Description: Start/stop unicorn Rack app server
|
10
|
+
### END INIT INFO
|
11
|
+
|
12
|
+
# Example init script, this can be used with nginx, too,
|
13
|
+
# since nginx and unicorn accept the same signals.
|
14
|
+
|
15
|
+
# Feel free to change any of the following variables for your app:
|
16
|
+
TIMEOUT=${TIMEOUT-60}
|
17
|
+
APP_ROOT=/home/x/my_app/current
|
18
|
+
PID=$APP_ROOT/tmp/pids/unicorn.pid
|
19
|
+
CMD="/usr/bin/unicorn -D -c $APP_ROOT/config/unicorn.rb"
|
20
|
+
INIT_CONF=$APP_ROOT/config/init.conf
|
21
|
+
UPGRADE_DELAY=${UPGRADE_DELAY-2}
|
22
|
+
action="$1"
|
23
|
+
set -u
|
24
|
+
|
25
|
+
test -f "$INIT_CONF" && . $INIT_CONF
|
26
|
+
|
27
|
+
OLD="$PID.oldbin"
|
28
|
+
|
29
|
+
cd $APP_ROOT || exit 1
|
30
|
+
|
31
|
+
sig () {
|
32
|
+
test -s "$PID" && kill -$1 $(cat $PID)
|
33
|
+
}
|
34
|
+
|
35
|
+
oldsig () {
|
36
|
+
test -s "$OLD" && kill -$1 $(cat $OLD)
|
37
|
+
}
|
38
|
+
|
39
|
+
case $action in
|
40
|
+
start)
|
41
|
+
sig 0 && echo >&2 "Already running" && exit 0
|
42
|
+
$CMD
|
43
|
+
;;
|
44
|
+
stop)
|
45
|
+
sig QUIT && exit 0
|
46
|
+
echo >&2 "Not running"
|
47
|
+
;;
|
48
|
+
force-stop)
|
49
|
+
sig TERM && exit 0
|
50
|
+
echo >&2 "Not running"
|
51
|
+
;;
|
52
|
+
restart|reload)
|
53
|
+
sig HUP && echo reloaded OK && exit 0
|
54
|
+
echo >&2 "Couldn't reload, starting '$CMD' instead"
|
55
|
+
$CMD
|
56
|
+
;;
|
57
|
+
upgrade)
|
58
|
+
if oldsig 0
|
59
|
+
then
|
60
|
+
echo >&2 "Old upgraded process still running with $OLD"
|
61
|
+
exit 1
|
62
|
+
fi
|
63
|
+
|
64
|
+
cur_pid=
|
65
|
+
if test -s "$PID"
|
66
|
+
then
|
67
|
+
cur_pid=$(cat $PID)
|
68
|
+
fi
|
69
|
+
|
70
|
+
if test -n "$cur_pid" &&
|
71
|
+
kill -USR2 "$cur_pid" &&
|
72
|
+
sleep $UPGRADE_DELAY &&
|
73
|
+
new_pid=$(cat $PID) &&
|
74
|
+
test x"$new_pid" != x"$cur_pid" &&
|
75
|
+
kill -0 "$new_pid" &&
|
76
|
+
kill -QUIT "$cur_pid"
|
77
|
+
then
|
78
|
+
n=$TIMEOUT
|
79
|
+
while kill -0 "$cur_pid" 2>/dev/null && test $n -ge 0
|
80
|
+
do
|
81
|
+
printf '.' && sleep 1 && n=$(( $n - 1 ))
|
82
|
+
done
|
83
|
+
echo
|
84
|
+
|
85
|
+
if test $n -lt 0 && kill -0 "$cur_pid" 2>/dev/null
|
86
|
+
then
|
87
|
+
echo >&2 "$cur_pid still running after $TIMEOUT seconds"
|
88
|
+
exit 1
|
89
|
+
fi
|
90
|
+
exit 0
|
91
|
+
fi
|
92
|
+
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
|
93
|
+
$CMD
|
94
|
+
;;
|
95
|
+
reopen-logs)
|
96
|
+
sig USR1
|
97
|
+
;;
|
98
|
+
*)
|
99
|
+
echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
|
100
|
+
exit 1
|
101
|
+
;;
|
102
|
+
esac
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
# Multi-Processing-safe monkey patch for Logger
|
3
|
+
#
|
4
|
+
# This monkey patch fixes the case where "preload_app true" is used and
|
5
|
+
# the application spawns a background thread upon being loaded.
|
6
|
+
#
|
7
|
+
# This removes all lock from the Logger code and solely relies on the
|
8
|
+
# underlying filesystem to handle write(2) system calls atomically when
|
9
|
+
# O_APPEND is used. This is safe in the presence of both multiple
|
10
|
+
# threads (native or green) and multiple processes when writing to
|
11
|
+
# a filesystem with POSIX O_APPEND semantics.
|
12
|
+
#
|
13
|
+
# It should be noted that the original locking on Logger could _never_ be
|
14
|
+
# considered reliable on non-POSIX filesystems with multiple processes,
|
15
|
+
# either, so nothing is lost in that case.
|
16
|
+
|
17
|
+
require 'logger'
|
18
|
+
class Logger::LogDevice
|
19
|
+
def write(message)
|
20
|
+
@dev.syswrite(message)
|
21
|
+
end
|
22
|
+
|
23
|
+
def close
|
24
|
+
@dev.close
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# example logrotate config file, I usually keep this in
|
2
|
+
# /etc/logrotate.d/unicorn_app on my Debian systems
|
3
|
+
#
|
4
|
+
# See the logrotate(8) manpage for more information:
|
5
|
+
# https://linux.die.net/man/8/logrotate
|
6
|
+
#
|
7
|
+
# public logrotate-related discussion in our archives:
|
8
|
+
# https://yhbt.net/unicorn-public/?q=logrotate
|
9
|
+
|
10
|
+
# Modify the following glob to match the logfiles your app writes to:
|
11
|
+
/var/log/unicorn_app/*.log {
|
12
|
+
# this first block is mostly just personal preference, though
|
13
|
+
# I wish logrotate offered an "hourly" option...
|
14
|
+
daily
|
15
|
+
missingok
|
16
|
+
rotate 180
|
17
|
+
compress # must use with delaycompress below
|
18
|
+
dateext
|
19
|
+
|
20
|
+
# this is important if using "compress" since we need to call
|
21
|
+
# the "lastaction" script below before compressing:
|
22
|
+
delaycompress
|
23
|
+
|
24
|
+
# note the lack of the evil "copytruncate" option in this
|
25
|
+
# config. Unicorn supports the USR1 signal and we send it
|
26
|
+
# as our "lastaction" action:
|
27
|
+
lastaction
|
28
|
+
# For systemd users, assuming you use two services
|
29
|
+
# (as recommended) to allow zero-downtime upgrades.
|
30
|
+
# Only one service needs to be started, but signaling
|
31
|
+
# both here is harmless as long as they're both enabled
|
32
|
+
systemctl kill -s SIGUSR1 unicorn@1.service
|
33
|
+
systemctl kill -s SIGUSR1 unicorn@2.service
|
34
|
+
|
35
|
+
# Examples for other process management systems appreciated
|
36
|
+
# Mail us at unicorn-public@yhbt.net
|
37
|
+
# (see above for archives)
|
38
|
+
|
39
|
+
# If you use a pid file and assuming your pid file
|
40
|
+
# is in /var/run/unicorn_app/pid
|
41
|
+
pid=/var/run/unicorn_app/pid
|
42
|
+
test -s $pid && kill -USR1 "$(cat $pid)"
|
43
|
+
endscript
|
44
|
+
}
|