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 CHANGED
@@ -1,3 +1,4 @@
1
+ v0.8.1 - safer timeout handling, more consistent reload behavior
1
2
  v0.8.0 - enforce Rack dependency, minor performance improvements and fixes
2
3
  v0.7.1 - minor fixes, cleanups and documentation improvements
3
4
  v0.7.0 - rack.version is 1.0
data/README CHANGED
@@ -1,4 +1,4 @@
1
- = Unicorn: Unix + LAN/localhost-only fork of Mongrel
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
- If you have web browser software for the World Wide Web
85
- (on the Information Superhighway), you may browse the code from
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 +-l/--listen+ switch to bind to a different
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. See the PHILOSOPHY
130
- and DESIGN documents for more details regarding this.
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 = "A small fast HTTP library and server for Rack applications."
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
- @request = HttpRequest.new(@logger)
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
- WORKERS.each_pair do |pid, worker|
381
- stat = worker.tempfile.stat
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} is too old, killing"
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, @app.call(@request.read(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 @config[:preload_app]
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.0".freeze
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
@@ -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.0"
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-26}
10
- s.description = %q{A small fast HTTP library and server for Rack applications.}
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{A small fast HTTP library and server for Rack applications.}
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.0
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-26 00:00:00 -07:00
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: A small fast HTTP library and server for Rack applications.
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: A small fast HTTP library and server for Rack applications.
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