unicorn 0.8.0 → 0.8.1

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.
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