unicorn 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/README +8 -10
- data/Rakefile +2 -2
- data/SIGNALS +1 -3
- data/lib/unicorn.rb +29 -13
- data/lib/unicorn/const.rb +1 -1
- data/lib/unicorn/http_request.rb +3 -1
- data/unicorn.gemspec +5 -5
- metadata +5 -5
data/CHANGELOG
CHANGED
data/README
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= Unicorn: Unix
|
1
|
+
= Unicorn: Rack HTTP server for Unix, fast clients and nothing else
|
2
2
|
|
3
3
|
== Features
|
4
4
|
|
@@ -81,9 +81,8 @@ You can get the latest source via git from the following locations
|
|
81
81
|
git://repo.or.cz/unicorn.git (mirror)
|
82
82
|
http://repo.or.cz/r/unicorn.git (mirror)
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
your web browser and download the latest snapshot tarballs here:
|
84
|
+
You may browse the code from the web and download the latest snapshot
|
85
|
+
tarballs here:
|
87
86
|
|
88
87
|
* http://git.bogomips.org/cgit/unicorn.git (cgit)
|
89
88
|
* http://repo.or.cz/w/unicorn.git (gitweb)
|
@@ -102,8 +101,8 @@ In RAILS_ROOT, run:
|
|
102
101
|
|
103
102
|
unicorn_rails
|
104
103
|
|
105
|
-
Unicorn will bind to all interfaces TCP port 8080 by default.
|
106
|
-
You may use the
|
104
|
+
Unicorn will bind to all interfaces on TCP port 8080 by default.
|
105
|
+
You may use the +--listen/-l+ switch to bind to a different
|
107
106
|
address:port or a UNIX socket.
|
108
107
|
|
109
108
|
=== Configuration File(s)
|
@@ -126,10 +125,9 @@ Like the creatures themselves, production deployments of Unicorn are
|
|
126
125
|
rare or even non-existent. There is NO WARRANTY whatsoever if anything
|
127
126
|
goes wrong, but let us know and we'll try our best to fix it.
|
128
127
|
|
129
|
-
Unicorn is designed to only serve fast clients
|
130
|
-
and DESIGN documents for more details
|
131
|
-
|
132
|
-
Rainbows are NOT included.
|
128
|
+
Unicorn is designed to only serve fast clients either on the local host
|
129
|
+
or a fast LAN. See the PHILOSOPHY and DESIGN documents for more details
|
130
|
+
regarding this.
|
133
131
|
|
134
132
|
== Known Issues
|
135
133
|
|
data/Rakefile
CHANGED
@@ -3,7 +3,7 @@ require 'rubygems'
|
|
3
3
|
require 'echoe'
|
4
4
|
|
5
5
|
Echoe.new("unicorn") do |p|
|
6
|
-
p.summary = "
|
6
|
+
p.summary = "Rack HTTP server for Unix, fast clients and nothing else"
|
7
7
|
p.author = "Eric Wong"
|
8
8
|
p.email = "normalperson@yhbt.net"
|
9
9
|
p.clean_pattern = ['ext/unicorn/http11/*.{bundle,so,o,obj,pdb,lib,def,exp}',
|
@@ -12,7 +12,7 @@ Echoe.new("unicorn") do |p|
|
|
12
12
|
'pkg', 'lib/*.bundle', '*.gem',
|
13
13
|
'site/output', '.config', 'coverage',
|
14
14
|
'test_*.log', 'log', 'doc']
|
15
|
-
p.url = "http://unicorn.bogomips.org"
|
15
|
+
p.url = "http://unicorn.bogomips.org/"
|
16
16
|
p.ignore_pattern = /^(pkg|site|projects|doc|log)|CVS|\.log/
|
17
17
|
p.need_tar_gz = false
|
18
18
|
p.need_tgz = true
|
data/SIGNALS
CHANGED
@@ -6,9 +6,7 @@ processes are documented here as well.
|
|
6
6
|
|
7
7
|
=== Master Process
|
8
8
|
|
9
|
-
* HUP - reload config file and gracefully restart all workers
|
10
|
-
If "preload_app" is false (the default), the application code
|
11
|
-
will be reloaded when workers are restarted as well.
|
9
|
+
* HUP - reload config file, app, and gracefully restart all workers
|
12
10
|
|
13
11
|
* INT/TERM - quick shutdown, kills all workers immediately
|
14
12
|
|
data/lib/unicorn.rb
CHANGED
@@ -41,6 +41,9 @@ module Unicorn
|
|
41
41
|
# signal queue used for self-piping
|
42
42
|
SIG_QUEUE = []
|
43
43
|
|
44
|
+
# constant lookups are faster and we're single-threaded/non-reentrant
|
45
|
+
REQUEST = HttpRequest.new
|
46
|
+
|
44
47
|
# We populate this at startup so we can figure out how to reexecute
|
45
48
|
# and upgrade the currently running instance of Unicorn
|
46
49
|
START_CTX = {
|
@@ -71,7 +74,7 @@ module Unicorn
|
|
71
74
|
@config = Configurator.new(options.merge(:use_defaults => true))
|
72
75
|
@listener_opts = {}
|
73
76
|
@config.commit!(self, :skip => [:listeners, :pid])
|
74
|
-
@
|
77
|
+
@orig_app = app
|
75
78
|
end
|
76
79
|
|
77
80
|
# Runs the thing. Returns self so you can run join on it
|
@@ -141,6 +144,10 @@ module Unicorn
|
|
141
144
|
def stdout_path=(path); redirect_io($stdout, path); end
|
142
145
|
def stderr_path=(path); redirect_io($stderr, path); end
|
143
146
|
|
147
|
+
def logger=(obj)
|
148
|
+
REQUEST.logger = @logger = obj
|
149
|
+
end
|
150
|
+
|
144
151
|
# sets the path for the PID file of the master process
|
145
152
|
def pid=(path)
|
146
153
|
if path
|
@@ -310,8 +317,7 @@ module Unicorn
|
|
310
317
|
self.pid = @pid.chomp('.oldbin') if @pid
|
311
318
|
proc_name 'master'
|
312
319
|
else
|
313
|
-
worker = WORKERS.delete(pid)
|
314
|
-
worker.tempfile.close rescue nil
|
320
|
+
worker = WORKERS.delete(pid) and worker.tempfile.close rescue nil
|
315
321
|
logger.info "reaped #{status.inspect} " \
|
316
322
|
"worker=#{worker.nr rescue 'unknown'}"
|
317
323
|
end
|
@@ -377,13 +383,20 @@ module Unicorn
|
|
377
383
|
# is stale for >@timeout seconds, then we'll kill the corresponding
|
378
384
|
# worker.
|
379
385
|
def murder_lazy_workers
|
380
|
-
|
381
|
-
|
386
|
+
diff = stat = nil
|
387
|
+
WORKERS.dup.each_pair do |pid, worker|
|
388
|
+
stat = begin
|
389
|
+
worker.tempfile.stat
|
390
|
+
rescue => e
|
391
|
+
logger.warn "worker=#{worker.nr} PID:#{pid} stat error: #{e.inspect}"
|
392
|
+
kill_worker(:QUIT, pid)
|
393
|
+
next
|
394
|
+
end
|
382
395
|
stat.mode == 0100000 and next
|
383
|
-
Time.now - stat.ctime <= @timeout and next
|
384
|
-
logger.error "worker=#{worker.nr} PID:#{pid}
|
396
|
+
(diff = (Time.now - stat.ctime)) <= @timeout and next
|
397
|
+
logger.error "worker=#{worker.nr} PID:#{pid} timeout " \
|
398
|
+
"(#{diff}s > #{@timeout}s), killing"
|
385
399
|
kill_worker(:KILL, pid) # take no prisoners for @timeout violations
|
386
|
-
worker.tempfile.close rescue nil
|
387
400
|
end
|
388
401
|
end
|
389
402
|
|
@@ -409,15 +422,15 @@ module Unicorn
|
|
409
422
|
def maintain_worker_count
|
410
423
|
(off = WORKERS.size - @worker_processes) == 0 and return
|
411
424
|
off < 0 and return spawn_missing_workers
|
412
|
-
WORKERS.each_pair { |pid,w|
|
425
|
+
WORKERS.dup.each_pair { |pid,w|
|
413
426
|
w.nr >= @worker_processes and kill_worker(:QUIT, pid) rescue nil
|
414
427
|
}
|
415
428
|
end
|
416
429
|
|
417
430
|
# once a client is accepted, it is processed in its entirety here
|
418
431
|
# in 3 easy steps: read request, call app, write app response
|
419
|
-
def process_client(client)
|
420
|
-
HttpResponse.write(client,
|
432
|
+
def process_client(app, client)
|
433
|
+
HttpResponse.write(client, app.call(REQUEST.read(client)))
|
421
434
|
# if we get any error, try to write something back to the client
|
422
435
|
# assuming we haven't closed the socket, but don't get hung up
|
423
436
|
# if the socket is already closed or broken. We'll always ensure
|
@@ -452,7 +465,7 @@ module Unicorn
|
|
452
465
|
worker.tempfile.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
453
466
|
@after_fork.call(self, worker) # can drop perms
|
454
467
|
@timeout /= 2.0 # halve it for select()
|
455
|
-
build_app! unless @
|
468
|
+
build_app! unless @preload_app
|
456
469
|
end
|
457
470
|
|
458
471
|
def reopen_worker_logs(worker_nr)
|
@@ -478,6 +491,7 @@ module Unicorn
|
|
478
491
|
trap(:QUIT) { alive = nil; LISTENERS.each { |s| s.close rescue nil } }
|
479
492
|
[:TERM, :INT].each { |sig| trap(sig) { exit!(0) } } # instant shutdown
|
480
493
|
@logger.info "worker=#{worker.nr} ready"
|
494
|
+
app = @app
|
481
495
|
|
482
496
|
begin
|
483
497
|
nr < 0 and reopen_worker_logs(worker.nr)
|
@@ -495,7 +509,7 @@ module Unicorn
|
|
495
509
|
|
496
510
|
ready.each do |sock|
|
497
511
|
begin
|
498
|
-
process_client(sock.accept_nonblock)
|
512
|
+
process_client(app, sock.accept_nonblock)
|
499
513
|
nr += 1
|
500
514
|
t == (ti = Time.now.to_i) or alive.chmod(t = ti)
|
501
515
|
rescue Errno::EAGAIN, Errno::ECONNABORTED
|
@@ -570,6 +584,8 @@ module Unicorn
|
|
570
584
|
@config.commit!(self)
|
571
585
|
kill_each_worker(:QUIT)
|
572
586
|
Unicorn::Util.reopen_logs
|
587
|
+
@app = @orig_app
|
588
|
+
build_app! if @preload_app
|
573
589
|
logger.info "done reloading config_file=#{@config.config_file}"
|
574
590
|
rescue Object => e
|
575
591
|
logger.error "error reloading config_file=#{@config.config_file}: " \
|
data/lib/unicorn/const.rb
CHANGED
@@ -5,7 +5,7 @@ module Unicorn
|
|
5
5
|
# gave about a 3% to 10% performance improvement over using the strings directly.
|
6
6
|
# Symbols did not really improve things much compared to constants.
|
7
7
|
module Const
|
8
|
-
UNICORN_VERSION="0.8.
|
8
|
+
UNICORN_VERSION="0.8.1".freeze
|
9
9
|
|
10
10
|
DEFAULT_HOST = "0.0.0.0".freeze # default TCP listen host address
|
11
11
|
DEFAULT_PORT = "8080".freeze # default TCP listen port
|
data/lib/unicorn/http_request.rb
CHANGED
@@ -12,6 +12,8 @@ module Unicorn
|
|
12
12
|
#
|
13
13
|
class HttpRequest
|
14
14
|
|
15
|
+
attr_accessor :logger
|
16
|
+
|
15
17
|
# default parameters we merge into the request env for Rack handlers
|
16
18
|
DEFAULTS = {
|
17
19
|
"rack.errors" => $stderr,
|
@@ -36,7 +38,7 @@ module Unicorn
|
|
36
38
|
PARSER = HttpParser.new
|
37
39
|
PARAMS = Hash.new
|
38
40
|
|
39
|
-
def initialize(logger)
|
41
|
+
def initialize(logger = Configurator::DEFAULT_LOGGER)
|
40
42
|
@logger = logger
|
41
43
|
end
|
42
44
|
|
data/unicorn.gemspec
CHANGED
@@ -2,24 +2,24 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{unicorn}
|
5
|
-
s.version = "0.8.
|
5
|
+
s.version = "0.8.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Eric Wong"]
|
9
|
-
s.date = %q{2009-05-
|
10
|
-
s.description = %q{
|
9
|
+
s.date = %q{2009-05-28}
|
10
|
+
s.description = %q{Rack HTTP server for Unix, fast clients and nothing else}
|
11
11
|
s.email = %q{normalperson@yhbt.net}
|
12
12
|
s.executables = ["unicorn", "unicorn_rails"]
|
13
13
|
s.extensions = ["ext/unicorn/http11/extconf.rb"]
|
14
14
|
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README", "TODO", "bin/unicorn", "bin/unicorn_rails", "ext/unicorn/http11/ext_help.h", "ext/unicorn/http11/extconf.rb", "ext/unicorn/http11/http11.c", "ext/unicorn/http11/http11_parser.h", "ext/unicorn/http11/http11_parser.rl", "ext/unicorn/http11/http11_parser_common.rl", "lib/unicorn.rb", "lib/unicorn/app/exec_cgi.rb", "lib/unicorn/app/old_rails.rb", "lib/unicorn/app/old_rails/static.rb", "lib/unicorn/cgi_wrapper.rb", "lib/unicorn/configurator.rb", "lib/unicorn/const.rb", "lib/unicorn/http_request.rb", "lib/unicorn/http_response.rb", "lib/unicorn/launcher.rb", "lib/unicorn/socket_helper.rb", "lib/unicorn/util.rb"]
|
15
15
|
s.files = [".document", ".gitignore", "CHANGELOG", "CONTRIBUTORS", "DESIGN", "GNUmakefile", "LICENSE", "Manifest", "PHILOSOPHY", "README", "Rakefile", "SIGNALS", "TODO", "TUNING", "bin/unicorn", "bin/unicorn_rails", "examples/init.sh", "ext/unicorn/http11/ext_help.h", "ext/unicorn/http11/extconf.rb", "ext/unicorn/http11/http11.c", "ext/unicorn/http11/http11_parser.h", "ext/unicorn/http11/http11_parser.rl", "ext/unicorn/http11/http11_parser_common.rl", "lib/unicorn.rb", "lib/unicorn/app/exec_cgi.rb", "lib/unicorn/app/old_rails.rb", "lib/unicorn/app/old_rails/static.rb", "lib/unicorn/cgi_wrapper.rb", "lib/unicorn/configurator.rb", "lib/unicorn/const.rb", "lib/unicorn/http_request.rb", "lib/unicorn/http_response.rb", "lib/unicorn/launcher.rb", "lib/unicorn/socket_helper.rb", "lib/unicorn/util.rb", "local.mk.sample", "setup.rb", "test/aggregate.rb", "test/benchmark/README", "test/benchmark/big_request.rb", "test/benchmark/dd.ru", "test/benchmark/request.rb", "test/benchmark/response.rb", "test/exec/README", "test/exec/test_exec.rb", "test/rails/app-1.2.3/.gitignore", "test/rails/app-1.2.3/Rakefile", "test/rails/app-1.2.3/app/controllers/application.rb", "test/rails/app-1.2.3/app/controllers/foo_controller.rb", "test/rails/app-1.2.3/app/helpers/application_helper.rb", "test/rails/app-1.2.3/config/boot.rb", "test/rails/app-1.2.3/config/database.yml", "test/rails/app-1.2.3/config/environment.rb", "test/rails/app-1.2.3/config/environments/development.rb", "test/rails/app-1.2.3/config/environments/production.rb", "test/rails/app-1.2.3/config/routes.rb", "test/rails/app-1.2.3/db/.gitignore", "test/rails/app-1.2.3/log/.gitignore", "test/rails/app-1.2.3/public/404.html", "test/rails/app-1.2.3/public/500.html", "test/rails/app-2.0.2/.gitignore", "test/rails/app-2.0.2/Rakefile", "test/rails/app-2.0.2/app/controllers/application.rb", "test/rails/app-2.0.2/app/controllers/foo_controller.rb", "test/rails/app-2.0.2/app/helpers/application_helper.rb", "test/rails/app-2.0.2/config/boot.rb", "test/rails/app-2.0.2/config/database.yml", "test/rails/app-2.0.2/config/environment.rb", "test/rails/app-2.0.2/config/environments/development.rb", "test/rails/app-2.0.2/config/environments/production.rb", "test/rails/app-2.0.2/config/routes.rb", "test/rails/app-2.0.2/db/.gitignore", "test/rails/app-2.0.2/log/.gitignore", "test/rails/app-2.0.2/public/404.html", "test/rails/app-2.0.2/public/500.html", "test/rails/app-2.1.2/.gitignore", "test/rails/app-2.1.2/Rakefile", "test/rails/app-2.1.2/app/controllers/application.rb", "test/rails/app-2.1.2/app/controllers/foo_controller.rb", "test/rails/app-2.1.2/app/helpers/application_helper.rb", "test/rails/app-2.1.2/config/boot.rb", "test/rails/app-2.1.2/config/database.yml", "test/rails/app-2.1.2/config/environment.rb", "test/rails/app-2.1.2/config/environments/development.rb", "test/rails/app-2.1.2/config/environments/production.rb", "test/rails/app-2.1.2/config/routes.rb", "test/rails/app-2.1.2/db/.gitignore", "test/rails/app-2.1.2/log/.gitignore", "test/rails/app-2.1.2/public/404.html", "test/rails/app-2.1.2/public/500.html", "test/rails/app-2.2.2/.gitignore", "test/rails/app-2.2.2/Rakefile", "test/rails/app-2.2.2/app/controllers/application.rb", "test/rails/app-2.2.2/app/controllers/foo_controller.rb", "test/rails/app-2.2.2/app/helpers/application_helper.rb", "test/rails/app-2.2.2/config/boot.rb", "test/rails/app-2.2.2/config/database.yml", "test/rails/app-2.2.2/config/environment.rb", "test/rails/app-2.2.2/config/environments/development.rb", "test/rails/app-2.2.2/config/environments/production.rb", "test/rails/app-2.2.2/config/routes.rb", "test/rails/app-2.2.2/db/.gitignore", "test/rails/app-2.2.2/log/.gitignore", "test/rails/app-2.2.2/public/404.html", "test/rails/app-2.2.2/public/500.html", "test/rails/app-2.3.2.1/.gitignore", "test/rails/app-2.3.2.1/Rakefile", "test/rails/app-2.3.2.1/app/controllers/application_controller.rb", "test/rails/app-2.3.2.1/app/controllers/foo_controller.rb", "test/rails/app-2.3.2.1/app/helpers/application_helper.rb", "test/rails/app-2.3.2.1/config/boot.rb", "test/rails/app-2.3.2.1/config/database.yml", "test/rails/app-2.3.2.1/config/environment.rb", "test/rails/app-2.3.2.1/config/environments/development.rb", "test/rails/app-2.3.2.1/config/environments/production.rb", "test/rails/app-2.3.2.1/config/routes.rb", "test/rails/app-2.3.2.1/db/.gitignore", "test/rails/app-2.3.2.1/log/.gitignore", "test/rails/app-2.3.2.1/public/404.html", "test/rails/app-2.3.2.1/public/500.html", "test/rails/test_rails.rb", "test/test_helper.rb", "test/unit/test_configurator.rb", "test/unit/test_http_parser.rb", "test/unit/test_request.rb", "test/unit/test_response.rb", "test/unit/test_server.rb", "test/unit/test_signals.rb", "test/unit/test_socket_helper.rb", "test/unit/test_upload.rb", "test/unit/test_util.rb", "unicorn.gemspec"]
|
16
16
|
s.has_rdoc = true
|
17
|
-
s.homepage = %q{http://unicorn.bogomips.org}
|
17
|
+
s.homepage = %q{http://unicorn.bogomips.org/}
|
18
18
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Unicorn", "--main", "README"]
|
19
19
|
s.require_paths = ["lib", "ext"]
|
20
20
|
s.rubyforge_project = %q{unicorn}
|
21
21
|
s.rubygems_version = %q{1.3.2}
|
22
|
-
s.summary = %q{
|
22
|
+
s.summary = %q{Rack HTTP server for Unix, fast clients and nothing else}
|
23
23
|
s.test_files = ["test/unit/test_configurator.rb", "test/unit/test_response.rb", "test/unit/test_request.rb", "test/unit/test_signals.rb", "test/unit/test_upload.rb", "test/unit/test_http_parser.rb", "test/unit/test_socket_helper.rb", "test/unit/test_util.rb", "test/unit/test_server.rb"]
|
24
24
|
|
25
25
|
if s.respond_to? :specification_version then
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unicorn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Wong
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-05-
|
12
|
+
date: 2009-05-28 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,7 +22,7 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: "0"
|
24
24
|
version:
|
25
|
-
description:
|
25
|
+
description: Rack HTTP server for Unix, fast clients and nothing else
|
26
26
|
email: normalperson@yhbt.net
|
27
27
|
executables:
|
28
28
|
- unicorn
|
@@ -188,7 +188,7 @@ files:
|
|
188
188
|
- test/unit/test_util.rb
|
189
189
|
- unicorn.gemspec
|
190
190
|
has_rdoc: true
|
191
|
-
homepage: http://unicorn.bogomips.org
|
191
|
+
homepage: http://unicorn.bogomips.org/
|
192
192
|
licenses: []
|
193
193
|
|
194
194
|
post_install_message:
|
@@ -220,7 +220,7 @@ rubyforge_project: unicorn
|
|
220
220
|
rubygems_version: 1.3.2
|
221
221
|
signing_key:
|
222
222
|
specification_version: 3
|
223
|
-
summary:
|
223
|
+
summary: Rack HTTP server for Unix, fast clients and nothing else
|
224
224
|
test_files:
|
225
225
|
- test/unit/test_configurator.rb
|
226
226
|
- test/unit/test_response.rb
|