giraffesoft-unicorn 0.93.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/.CHANGELOG.old +25 -0
  2. data/.document +16 -0
  3. data/.gitignore +20 -0
  4. data/.mailmap +26 -0
  5. data/CONTRIBUTORS +31 -0
  6. data/COPYING +339 -0
  7. data/DESIGN +105 -0
  8. data/Documentation/.gitignore +5 -0
  9. data/Documentation/GNUmakefile +30 -0
  10. data/Documentation/unicorn.1.txt +167 -0
  11. data/Documentation/unicorn_rails.1.txt +169 -0
  12. data/GIT-VERSION-GEN +40 -0
  13. data/GNUmakefile +270 -0
  14. data/HACKING +113 -0
  15. data/KNOWN_ISSUES +40 -0
  16. data/LICENSE +55 -0
  17. data/PHILOSOPHY +144 -0
  18. data/README +153 -0
  19. data/Rakefile +108 -0
  20. data/SIGNALS +97 -0
  21. data/TODO +16 -0
  22. data/TUNING +70 -0
  23. data/bin/unicorn +165 -0
  24. data/bin/unicorn_rails +208 -0
  25. data/examples/echo.ru +27 -0
  26. data/examples/git.ru +13 -0
  27. data/examples/init.sh +53 -0
  28. data/ext/unicorn_http/c_util.h +107 -0
  29. data/ext/unicorn_http/common_field_optimization.h +111 -0
  30. data/ext/unicorn_http/ext_help.h +73 -0
  31. data/ext/unicorn_http/extconf.rb +14 -0
  32. data/ext/unicorn_http/global_variables.h +91 -0
  33. data/ext/unicorn_http/unicorn_http.rl +715 -0
  34. data/ext/unicorn_http/unicorn_http_common.rl +74 -0
  35. data/lib/unicorn.rb +730 -0
  36. data/lib/unicorn/app/exec_cgi.rb +150 -0
  37. data/lib/unicorn/app/inetd.rb +109 -0
  38. data/lib/unicorn/app/old_rails.rb +31 -0
  39. data/lib/unicorn/app/old_rails/static.rb +60 -0
  40. data/lib/unicorn/cgi_wrapper.rb +145 -0
  41. data/lib/unicorn/configurator.rb +403 -0
  42. data/lib/unicorn/const.rb +37 -0
  43. data/lib/unicorn/http_request.rb +74 -0
  44. data/lib/unicorn/http_response.rb +74 -0
  45. data/lib/unicorn/launcher.rb +39 -0
  46. data/lib/unicorn/socket_helper.rb +138 -0
  47. data/lib/unicorn/tee_input.rb +174 -0
  48. data/lib/unicorn/util.rb +64 -0
  49. data/local.mk.sample +53 -0
  50. data/setup.rb +1586 -0
  51. data/test/aggregate.rb +15 -0
  52. data/test/benchmark/README +50 -0
  53. data/test/benchmark/dd.ru +18 -0
  54. data/test/exec/README +5 -0
  55. data/test/exec/test_exec.rb +855 -0
  56. data/test/rails/app-1.2.3/.gitignore +2 -0
  57. data/test/rails/app-1.2.3/Rakefile +7 -0
  58. data/test/rails/app-1.2.3/app/controllers/application.rb +6 -0
  59. data/test/rails/app-1.2.3/app/controllers/foo_controller.rb +36 -0
  60. data/test/rails/app-1.2.3/app/helpers/application_helper.rb +4 -0
  61. data/test/rails/app-1.2.3/config/boot.rb +11 -0
  62. data/test/rails/app-1.2.3/config/database.yml +12 -0
  63. data/test/rails/app-1.2.3/config/environment.rb +13 -0
  64. data/test/rails/app-1.2.3/config/environments/development.rb +9 -0
  65. data/test/rails/app-1.2.3/config/environments/production.rb +5 -0
  66. data/test/rails/app-1.2.3/config/routes.rb +6 -0
  67. data/test/rails/app-1.2.3/db/.gitignore +0 -0
  68. data/test/rails/app-1.2.3/public/404.html +1 -0
  69. data/test/rails/app-1.2.3/public/500.html +1 -0
  70. data/test/rails/app-2.0.2/.gitignore +2 -0
  71. data/test/rails/app-2.0.2/Rakefile +7 -0
  72. data/test/rails/app-2.0.2/app/controllers/application.rb +4 -0
  73. data/test/rails/app-2.0.2/app/controllers/foo_controller.rb +36 -0
  74. data/test/rails/app-2.0.2/app/helpers/application_helper.rb +4 -0
  75. data/test/rails/app-2.0.2/config/boot.rb +11 -0
  76. data/test/rails/app-2.0.2/config/database.yml +12 -0
  77. data/test/rails/app-2.0.2/config/environment.rb +17 -0
  78. data/test/rails/app-2.0.2/config/environments/development.rb +8 -0
  79. data/test/rails/app-2.0.2/config/environments/production.rb +5 -0
  80. data/test/rails/app-2.0.2/config/routes.rb +6 -0
  81. data/test/rails/app-2.0.2/db/.gitignore +0 -0
  82. data/test/rails/app-2.0.2/public/404.html +1 -0
  83. data/test/rails/app-2.0.2/public/500.html +1 -0
  84. data/test/rails/app-2.1.2/.gitignore +2 -0
  85. data/test/rails/app-2.1.2/Rakefile +7 -0
  86. data/test/rails/app-2.1.2/app/controllers/application.rb +4 -0
  87. data/test/rails/app-2.1.2/app/controllers/foo_controller.rb +36 -0
  88. data/test/rails/app-2.1.2/app/helpers/application_helper.rb +4 -0
  89. data/test/rails/app-2.1.2/config/boot.rb +111 -0
  90. data/test/rails/app-2.1.2/config/database.yml +12 -0
  91. data/test/rails/app-2.1.2/config/environment.rb +17 -0
  92. data/test/rails/app-2.1.2/config/environments/development.rb +7 -0
  93. data/test/rails/app-2.1.2/config/environments/production.rb +5 -0
  94. data/test/rails/app-2.1.2/config/routes.rb +6 -0
  95. data/test/rails/app-2.1.2/db/.gitignore +0 -0
  96. data/test/rails/app-2.1.2/public/404.html +1 -0
  97. data/test/rails/app-2.1.2/public/500.html +1 -0
  98. data/test/rails/app-2.2.2/.gitignore +2 -0
  99. data/test/rails/app-2.2.2/Rakefile +7 -0
  100. data/test/rails/app-2.2.2/app/controllers/application.rb +4 -0
  101. data/test/rails/app-2.2.2/app/controllers/foo_controller.rb +36 -0
  102. data/test/rails/app-2.2.2/app/helpers/application_helper.rb +4 -0
  103. data/test/rails/app-2.2.2/config/boot.rb +111 -0
  104. data/test/rails/app-2.2.2/config/database.yml +12 -0
  105. data/test/rails/app-2.2.2/config/environment.rb +17 -0
  106. data/test/rails/app-2.2.2/config/environments/development.rb +7 -0
  107. data/test/rails/app-2.2.2/config/environments/production.rb +5 -0
  108. data/test/rails/app-2.2.2/config/routes.rb +6 -0
  109. data/test/rails/app-2.2.2/db/.gitignore +0 -0
  110. data/test/rails/app-2.2.2/public/404.html +1 -0
  111. data/test/rails/app-2.2.2/public/500.html +1 -0
  112. data/test/rails/app-2.3.3.1/.gitignore +2 -0
  113. data/test/rails/app-2.3.3.1/Rakefile +7 -0
  114. data/test/rails/app-2.3.3.1/app/controllers/application_controller.rb +5 -0
  115. data/test/rails/app-2.3.3.1/app/controllers/foo_controller.rb +36 -0
  116. data/test/rails/app-2.3.3.1/app/helpers/application_helper.rb +4 -0
  117. data/test/rails/app-2.3.3.1/config/boot.rb +109 -0
  118. data/test/rails/app-2.3.3.1/config/database.yml +12 -0
  119. data/test/rails/app-2.3.3.1/config/environment.rb +17 -0
  120. data/test/rails/app-2.3.3.1/config/environments/development.rb +7 -0
  121. data/test/rails/app-2.3.3.1/config/environments/production.rb +6 -0
  122. data/test/rails/app-2.3.3.1/config/routes.rb +6 -0
  123. data/test/rails/app-2.3.3.1/db/.gitignore +0 -0
  124. data/test/rails/app-2.3.3.1/public/404.html +1 -0
  125. data/test/rails/app-2.3.3.1/public/500.html +1 -0
  126. data/test/rails/app-2.3.3.1/public/x.txt +1 -0
  127. data/test/rails/test_rails.rb +280 -0
  128. data/test/test_helper.rb +296 -0
  129. data/test/unit/test_configurator.rb +150 -0
  130. data/test/unit/test_http_parser.rb +492 -0
  131. data/test/unit/test_http_parser_ng.rb +308 -0
  132. data/test/unit/test_request.rb +184 -0
  133. data/test/unit/test_response.rb +110 -0
  134. data/test/unit/test_server.rb +188 -0
  135. data/test/unit/test_signals.rb +202 -0
  136. data/test/unit/test_socket_helper.rb +133 -0
  137. data/test/unit/test_tee_input.rb +229 -0
  138. data/test/unit/test_upload.rb +297 -0
  139. data/test/unit/test_util.rb +96 -0
  140. data/unicorn.gemspec +42 -0
  141. metadata +228 -0
data/SIGNALS ADDED
@@ -0,0 +1,97 @@
1
+ == Signal handling
2
+
3
+ In general, signals need only be sent to the master process. However,
4
+ the signals Unicorn uses internally to communicate with the worker
5
+ processes are documented here as well. With the exception of TTIN/TTOU,
6
+ signal handling matches the behavior of {nginx}[http://nginx.net/] so it
7
+ should be possible to easily share process management scripts between
8
+ Unicorn and nginx.
9
+
10
+ === Master Process
11
+
12
+ * HUP - reload config file, app, and gracefully restart all workers
13
+
14
+ * INT/TERM - quick shutdown, kills all workers immediately
15
+
16
+ * QUIT - graceful shutdown, waits for workers to finish their
17
+ current request before finishing.
18
+
19
+ * USR1 - reopen all logs owned by the master and all workers
20
+ See Unicorn::Util.reopen_logs for what is considered a log.
21
+
22
+ * USR2 - reexecute the running binary. A separate QUIT
23
+ should be sent to the original process once the child is verified to
24
+ be up and running.
25
+
26
+ * WINCH - gracefully stops workers but keep the master running.
27
+ This will only work for daemonized processes.
28
+
29
+ * TTIN - increment the number of worker processes by one
30
+
31
+ * TTOU - decrement the number of worker processes by one
32
+
33
+ === Worker Processes
34
+
35
+ Sending signals directly to the worker processes should not normally be
36
+ needed. If the master process is running, any exited worker will be
37
+ automatically respawned.
38
+
39
+ * INT/TERM - Quick shutdown, immediately exit.
40
+ Unless WINCH has been sent to the master (or the master is killed),
41
+ the master process will respawn a worker to replace this one.
42
+
43
+ * QUIT - Gracefully exit after finishing the current request.
44
+ Unless WINCH has been sent to the master (or the master is killed),
45
+ the master process will respawn a worker to replace this one.
46
+
47
+ * USR1 - Reopen all logs owned by the worker process.
48
+ See Unicorn::Util.reopen_logs for what is considered a log.
49
+ Log files are not reopened until it is done processing
50
+ the current request, so multiple log lines for one request
51
+ (as done by Rails) will not be split across multiple logs.
52
+
53
+ === Procedure to replace a running unicorn executable
54
+
55
+ You may replace a running instance of unicorn with a new one without
56
+ losing any incoming connections. Doing so will reload all of your
57
+ application code, Unicorn config, Ruby executable, and all libraries.
58
+ The only things that will not change (due to OS limitations) are:
59
+
60
+ 1. The path to the unicorn executable script. If you want to change to
61
+ a different installation of Ruby, you can modify the shebang
62
+ line to point to your alternative interpreter.
63
+
64
+ The procedure is exactly like that of nginx:
65
+
66
+ 1. Send USR2 to the master process
67
+
68
+ 2. Check your process manager or pid files to see if a new master spawned
69
+ successfully. If you're using a pid file, the old process will have
70
+ ".oldbin" appended to its path. You should have two master instances
71
+ of unicorn running now, both of which will have workers servicing
72
+ requests. Your process tree should look something like this:
73
+
74
+ unicorn master (old)
75
+ \_ unicorn worker[0]
76
+ \_ unicorn worker[1]
77
+ \_ unicorn worker[2]
78
+ \_ unicorn worker[3]
79
+ \_ unicorn master
80
+ \_ unicorn worker[0]
81
+ \_ unicorn worker[1]
82
+ \_ unicorn worker[2]
83
+ \_ unicorn worker[3]
84
+
85
+ 3. You can now send WINCH to the old master process so only the new workers
86
+ serve requests. If your unicorn process is bound to an interactive
87
+ terminal, you can skip this step. Step 5 will be more difficult but
88
+ you can also skip it if your process is not daemonized.
89
+
90
+ 4. You should now ensure that everything is running correctly with the
91
+ new workers as the old workers die off.
92
+
93
+ 5. If everything seems ok, then send QUIT to the old master. You're done!
94
+
95
+ If something is broken, then send HUP to the old master to reload
96
+ the config and restart its workers. Then send QUIT to the new master
97
+ process.
data/TODO ADDED
@@ -0,0 +1,16 @@
1
+ * Documentation improvements
2
+
3
+ * ensure test suite passes on non-GNU/Linux systems
4
+ (likely that it already does)
5
+
6
+ * consider adding "working_directory" directive to Configurator
7
+ since START_CTX is ugly...
8
+
9
+ * consider adding user switching support (ugh...)
10
+ This makes more sense for Rainbows!, but some folks use it already...
11
+
12
+ * fix const-correctness in HTTP parser
13
+
14
+ * performance validation (esp. TeeInput)
15
+
16
+ * improve test suite (steal from Rainbows!, probably...)
data/TUNING ADDED
@@ -0,0 +1,70 @@
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
+
11
+ * Setting a very low value for the :backlog parameter in "listen"
12
+ directives can allow failover to happen more quickly if your
13
+ cluster is configured for it.
14
+
15
+ * If you're doing extremely simple benchmarks and getting connection
16
+ errors under high request rates, increasing your :backlog parameter
17
+ above the already-generous default of 1024 can help avoid connection
18
+ errors. Keep in mind this is not recommended for real traffic if
19
+ you have another machine to failover to (see above).
20
+
21
+ * :rcvbuf and :sndbuf parameters generally do not need to be set for TCP
22
+ listeners under Linux 2.6 because auto-tuning is enabled. UNIX domain
23
+ sockets do not have auto-tuning buffer sizes; so increasing those will
24
+ allow syscalls and task switches to be saved for larger requests
25
+ and responses.
26
+
27
+ * Setting "preload_app true" can allow copy-on-write-friendly GC to
28
+ be used to save memory. It will probably not work out of the box with
29
+ applications that open sockets or perform random I/O on files.
30
+ Databases like TokyoCabinet use concurrency-safe pread()/pwrite()
31
+ functions for safe sharing of database file descriptors across
32
+ processes.
33
+
34
+ * On POSIX-compliant filesystems, it is safe for multiple threads or
35
+ processes to append to one log file as long as all the processes are
36
+ have them unbuffered (File#sync = true) or they are
37
+ record(line)-buffered in userspace.
38
+
39
+ * worker_processes should be scaled to the number of processes your
40
+ backend system(s) can support. DO NOT scale it to the number of
41
+ external network clients your application expects to be serving.
42
+ Unicorn is NOT for serving slow clients, that is the job of nginx.
43
+
44
+ == Kernel Parameters (Linux sysctl)
45
+
46
+ WARNING: Do not change system parameters unless you know what you're doing!
47
+
48
+ * net.core.rmem_max and net.core.wmem_max can increase the allowed
49
+ size of :rcvbuf and :sndbuf respectively. This is mostly only useful
50
+ for UNIX domain sockets which do not have auto-tuning buffer sizes.
51
+
52
+ * For load testing/benchmarking with UNIX domain sockets, you should
53
+ consider increasing net.core.somaxconn or else nginx will start
54
+ failing to connect under heavy load. You may also consider setting
55
+ a higher :backlog to listen on as noted earlier.
56
+
57
+ * If you're running out of local ports, consider lowering
58
+ net.ipv4.tcp_fin_timeout to 20-30 (default: 60 seconds). Also
59
+ consider widening the usable port range by changing
60
+ net.ipv4.ip_local_port_range.
61
+
62
+ * Setting net.ipv4.tcp_timestamps=1 will also allow setting
63
+ net.ipv4.tcp_tw_reuse=1 and net.ipv4.tcp_tw_recycle=1, which along
64
+ with the above settings can slow down port exhaustion. Not all
65
+ networks are compatible with these settings, check with your friendly
66
+ network administrator before changing these.
67
+
68
+ * Increasing the MTU size can reduce framing overhead for larger
69
+ transfers. One often-overlooked detail is that the loopback
70
+ device (usually "lo") can have its MTU increased, too.
data/bin/unicorn ADDED
@@ -0,0 +1,165 @@
1
+ #!/home/ew/bin/ruby
2
+ # -*- encoding: binary -*-
3
+ require 'unicorn/launcher'
4
+ require 'optparse'
5
+
6
+ env = "development"
7
+ daemonize = false
8
+ listeners = []
9
+ options = { :listeners => listeners }
10
+ host, port = Unicorn::Const::DEFAULT_HOST, Unicorn::Const::DEFAULT_PORT
11
+ set_listener = false
12
+
13
+ opts = OptionParser.new("", 24, ' ') do |opts|
14
+ opts.banner = "Usage: #{File.basename($0)} " \
15
+ "[ruby options] [unicorn options] [rackup config file]"
16
+
17
+ opts.separator "Ruby options:"
18
+
19
+ lineno = 1
20
+ opts.on("-e", "--eval LINE", "evaluate a LINE of code") do |line|
21
+ eval line, TOPLEVEL_BINDING, "-e", lineno
22
+ lineno += 1
23
+ end
24
+
25
+ opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") do
26
+ $DEBUG = true
27
+ end
28
+
29
+ opts.on("-w", "--warn", "turn warnings on for your script") do
30
+ $-w = true
31
+ end
32
+
33
+ opts.on("-I", "--include PATH",
34
+ "specify $LOAD_PATH (may be used more than once)") do |path|
35
+ $LOAD_PATH.unshift(*path.split(/:/))
36
+ end
37
+
38
+ opts.on("-r", "--require LIBRARY",
39
+ "require the library, before executing your script") do |library|
40
+ require library
41
+ end
42
+
43
+ opts.separator "Unicorn options:"
44
+
45
+ # some of these switches exist for rackup command-line compatibility,
46
+
47
+ opts.on("-o", "--host HOST",
48
+ "listen on HOST (default: #{Unicorn::Const::DEFAULT_HOST})") do |h|
49
+ host = h
50
+ set_listener = true
51
+ end
52
+
53
+ opts.on("-p", "--port PORT",
54
+ "use PORT (default: #{Unicorn::Const::DEFAULT_PORT})") do |p|
55
+ port = p.to_i
56
+ set_listener = true
57
+ end
58
+
59
+ opts.on("-E", "--env ENVIRONMENT",
60
+ "use ENVIRONMENT for defaults (default: development)") do |e|
61
+ env = e
62
+ end
63
+
64
+ opts.on("-D", "--daemonize", "run daemonized in the background") do |d|
65
+ daemonize = d ? true : false
66
+ end
67
+
68
+ opts.on("-P", "--pid FILE", "DEPRECATED") do |f|
69
+ warn %q{Use of --pid/-P is strongly discouraged}
70
+ warn %q{Use the 'pid' directive in the Unicorn config file instead}
71
+ options[:pid] = File.expand_path(f)
72
+ end
73
+
74
+ opts.on("-s", "--server SERVER",
75
+ "this flag only exists for compatibility") do |s|
76
+ warn "-s/--server only exists for compatibility with rackup"
77
+ end
78
+
79
+ # Unicorn-specific stuff
80
+ opts.on("-l", "--listen {HOST:PORT|PATH}",
81
+ "listen on HOST:PORT or PATH",
82
+ "this may be specified multiple times",
83
+ "(default: #{Unicorn::Const::DEFAULT_LISTEN})") do |address|
84
+ listeners << address
85
+ end
86
+
87
+ opts.on("-c", "--config-file FILE", "Unicorn-specific config file") do |f|
88
+ options[:config_file] = File.expand_path(f)
89
+ end
90
+
91
+ # I'm avoiding Unicorn-specific config options on the command-line.
92
+ # IMNSHO, config options on the command-line are redundant given
93
+ # config files and make things unnecessarily complicated with multiple
94
+ # places to look for a config option.
95
+
96
+ opts.separator "Common options:"
97
+
98
+ opts.on_tail("-h", "--help", "Show this message") do
99
+ puts opts.to_s.gsub(/^.*DEPRECATED.*$/s, '')
100
+ exit
101
+ end
102
+
103
+ opts.on_tail("-v", "--version", "Show version") do
104
+ puts "unicorn v#{Unicorn::Const::UNICORN_VERSION}"
105
+ exit
106
+ end
107
+
108
+ opts.parse! ARGV
109
+ end
110
+
111
+ config = ARGV[0] || "config.ru"
112
+ abort "configuration file #{config} not found" unless File.exist?(config)
113
+
114
+ if config =~ /\.ru$/
115
+ # parse embedded command-line options in config.ru comments
116
+ if File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) } =~ /^#\\(.*)/
117
+ opts.parse! $1.split(/\s+/)
118
+ end
119
+ end
120
+
121
+ require 'pp' if $DEBUG
122
+
123
+ app = lambda do ||
124
+ # require Rack as late as possible in case $LOAD_PATH is modified
125
+ # in config.ru or command-line
126
+ inner_app = case config
127
+ when /\.ru$/
128
+ raw = File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) }
129
+ raw.sub!(/^__END__\n.*/, '')
130
+ eval("Rack::Builder.new {(#{raw}\n)}.to_app", nil, config)
131
+ else
132
+ require config
133
+ Object.const_get(File.basename(config, '.rb').capitalize)
134
+ end
135
+ pp({ :inner_app => inner_app }) if $DEBUG
136
+ case env
137
+ when "development"
138
+ Rack::Builder.new do
139
+ use Rack::CommonLogger, $stderr
140
+ use Rack::ShowExceptions
141
+ use Rack::Lint
142
+ run inner_app
143
+ end.to_app
144
+ when "deployment"
145
+ Rack::Builder.new do
146
+ use Rack::CommonLogger, $stderr
147
+ run inner_app
148
+ end.to_app
149
+ else
150
+ inner_app
151
+ end
152
+ end
153
+
154
+ listeners << "#{host}:#{port}" if set_listener
155
+
156
+ if $DEBUG
157
+ pp({
158
+ :unicorn_options => options,
159
+ :app => app,
160
+ :daemonize => daemonize,
161
+ })
162
+ end
163
+
164
+ Unicorn::Launcher.daemonize! if daemonize
165
+ Unicorn.run(app, options)
data/bin/unicorn_rails ADDED
@@ -0,0 +1,208 @@
1
+ #!/home/ew/bin/ruby
2
+ # -*- encoding: binary -*-
3
+ require 'unicorn/launcher'
4
+ require 'optparse'
5
+ require 'fileutils'
6
+
7
+ rails_pid = "#{Unicorn::HttpServer::START_CTX[:cwd]}/tmp/pids/unicorn.pid"
8
+ cmd = File.basename($0)
9
+ daemonize = false
10
+ listeners = []
11
+ options = { :listeners => listeners }
12
+ host, port = Unicorn::Const::DEFAULT_HOST, Unicorn::Const::DEFAULT_PORT
13
+ set_listener = false
14
+ ENV['RAILS_ENV'] ||= "development"
15
+
16
+ opts = OptionParser.new("", 24, ' ') do |opts|
17
+ opts.banner = "Usage: #{cmd} " \
18
+ "[ruby options] [#{cmd} options] [rackup config file]"
19
+ opts.separator "Ruby options:"
20
+
21
+ lineno = 1
22
+ opts.on("-e", "--eval LINE", "evaluate a LINE of code") do |line|
23
+ eval line, TOPLEVEL_BINDING, "-e", lineno
24
+ lineno += 1
25
+ end
26
+
27
+ opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") do
28
+ $DEBUG = true
29
+ end
30
+
31
+ opts.on("-w", "--warn", "turn warnings on for your script") do
32
+ $-w = true
33
+ end
34
+
35
+ opts.on("-I", "--include PATH",
36
+ "specify $LOAD_PATH (may be used more than once)") do |path|
37
+ $LOAD_PATH.unshift(*path.split(/:/))
38
+ end
39
+
40
+ opts.on("-r", "--require LIBRARY",
41
+ "require the library, before executing your script") do |library|
42
+ require library
43
+ end
44
+
45
+ opts.separator "#{cmd} options:"
46
+
47
+ # some of these switches exist for rackup command-line compatibility,
48
+
49
+ opts.on("-o", "--host HOST",
50
+ "listen on HOST (default: #{Unicorn::Const::DEFAULT_HOST})") do |h|
51
+ host = h
52
+ set_listener = true
53
+ end
54
+
55
+ opts.on("-p", "--port PORT", "use PORT (default: #{port})") do |p|
56
+ port = p.to_i
57
+ set_listener = true
58
+ end
59
+
60
+ opts.on("-E", "--env RAILS_ENV",
61
+ "use RAILS_ENV for defaults (default: development)") do |e|
62
+ ENV['RAILS_ENV'] = e
63
+ end
64
+
65
+ opts.on("-D", "--daemonize", "run daemonized in the background") do |d|
66
+ daemonize = d ? true : false
67
+ end
68
+
69
+ # Unicorn-specific stuff
70
+ opts.on("-l", "--listen {HOST:PORT|PATH}",
71
+ "listen on HOST:PORT or PATH",
72
+ "this may be specified multiple times",
73
+ "(default: #{Unicorn::Const::DEFAULT_LISTEN})") do |address|
74
+ listeners << address
75
+ end
76
+
77
+ opts.on("-c", "--config-file FILE", "Unicorn-specific config file") do |f|
78
+ options[:config_file] = File.expand_path(f)
79
+ end
80
+
81
+ opts.on("-P PATH", "DEPRECATED") do |v|
82
+ warn %q{Use of -P is ambiguous and discouraged}
83
+ warn %q{Use --path or RAILS_RELATIVE_URL_ROOT instead}
84
+ ENV['RAILS_RELATIVE_URL_ROOT'] = v
85
+ end
86
+
87
+ opts.on("--path PATH", "Runs Rails app mounted at a specific path.",
88
+ "(default: /)") do |v|
89
+ ENV['RAILS_RELATIVE_URL_ROOT'] = v
90
+ end
91
+
92
+ # I'm avoiding Unicorn-specific config options on the command-line.
93
+ # IMNSHO, config options on the command-line are redundant given
94
+ # config files and make things unnecessarily complicated with multiple
95
+ # places to look for a config option.
96
+
97
+ opts.separator "Common options:"
98
+
99
+ opts.on_tail("-h", "--help", "Show this message") do
100
+ puts opts.to_s.gsub(/^.*DEPRECATED.*$/s, '')
101
+ exit
102
+ end
103
+
104
+ opts.on_tail("-v", "--version", "Show version") do
105
+ puts " v#{Unicorn::Const::UNICORN_VERSION}"
106
+ exit
107
+ end
108
+
109
+ opts.parse! ARGV
110
+ end
111
+
112
+ config = ARGV[0] || (File.exist?('config.ru') ? 'config.ru' : nil)
113
+
114
+ if config && config =~ /\.ru$/
115
+ # parse embedded command-line options in config.ru comments
116
+ if File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) } =~ /^#\\(.*)/
117
+ opts.parse! $1.split(/\s+/)
118
+ end
119
+ end
120
+
121
+ require 'pp' if $DEBUG
122
+
123
+ # this won't run until after forking if preload_app is false
124
+ app = lambda do ||
125
+ # Load Rails and the private version of Rack it bundles.
126
+ begin
127
+ require 'config/boot'
128
+ rescue LoadError => err
129
+ abort "#$0 must be run inside RAILS_ROOT: #{err.inspect}"
130
+ end
131
+ defined?(::RAILS_ROOT) or abort "RAILS_ROOT not defined by config/boot"
132
+ defined?(::RAILS_ENV) or abort "RAILS_ENV not defined by config/boot"
133
+ defined?(::Rails::VERSION::STRING) or
134
+ abort "Rails::VERSION::STRING not defined by config/boot"
135
+
136
+ inner_app = case config
137
+ when nil
138
+ require 'config/environment'
139
+
140
+ # it seems Rails >=2.2 support Rack, but only >=2.3 requires it
141
+ old_rails = case ::Rails::VERSION::MAJOR
142
+ when 0, 1 then true
143
+ when 2 then Rails::VERSION::MINOR < 3 ? true : false
144
+ else
145
+ false
146
+ end
147
+
148
+ if old_rails
149
+ require 'unicorn/app/old_rails'
150
+ Unicorn::App::OldRails.new
151
+ else
152
+ ActionController::Dispatcher.new
153
+ end
154
+ when /\.ru$/
155
+ raw = File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) }
156
+ raw.sub!(/^__END__\n.*/, '')
157
+ eval("Rack::Builder.new {(#{raw}\n)}.to_app", nil, config)
158
+ else
159
+ require config
160
+ Object.const_get(File.basename(config, '.rb').capitalize)
161
+ end
162
+
163
+ Rack::Builder.new do
164
+ map_path = ENV['RAILS_RELATIVE_URL_ROOT'] || '/'
165
+ if inner_app.class.to_s == "Unicorn::App::OldRails"
166
+ if map_path != '/'
167
+ # patches + tests welcome, but I really cbf to deal with this
168
+ # since all apps I've ever dealt with just use "/" ...
169
+ $stderr.puts "relative URL roots may not work for older Rails"
170
+ end
171
+ $stderr.puts "LogTailer not available for Rails < 2.3" unless daemonize
172
+ $stderr.puts "Debugger not available" if $DEBUG
173
+ map(map_path) do
174
+ require 'unicorn/app/old_rails/static'
175
+ use Unicorn::App::OldRails::Static
176
+ run inner_app
177
+ end
178
+ else
179
+ use Rails::Rack::LogTailer unless daemonize
180
+ use Rails::Rack::Debugger if $DEBUG
181
+ map(map_path) do
182
+ use Rails::Rack::Static
183
+ run inner_app
184
+ end
185
+ end
186
+ end.to_app
187
+ end
188
+
189
+ listeners << "#{host}:#{port}" if set_listener
190
+
191
+ if $DEBUG
192
+ pp({
193
+ :unicorn_options => options,
194
+ :app => app,
195
+ :daemonize => daemonize,
196
+ })
197
+ end
198
+
199
+ # ensure Rails standard tmp paths exist
200
+ %w(cache pids sessions sockets).each do |dir|
201
+ FileUtils.mkdir_p("tmp/#{dir}")
202
+ end
203
+
204
+ if daemonize
205
+ options[:pid] = rails_pid
206
+ Unicorn::Launcher.daemonize!
207
+ end
208
+ Unicorn.run(app, options)