unicorn 2.0.0pre3 → 2.0.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.
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v2.0.0pre3.GIT
4
+ DEF_VER=v2.0.0.GIT
5
5
 
6
6
  LF='
7
7
  '
data/GNUmakefile CHANGED
@@ -175,7 +175,7 @@ NEWS: GIT-VERSION-FILE .manifest
175
175
  $(RAKE) -s news_rdoc > $@+
176
176
  mv $@+ $@
177
177
 
178
- SINCE = 1.1.4
178
+ SINCE = 1.1.5
179
179
  ChangeLog: LOG_VERSION = \
180
180
  $(shell git rev-parse -q "$(GIT_VERSION)" >/dev/null 2>&1 && \
181
181
  echo $(GIT_VERSION) || git describe)
@@ -195,7 +195,7 @@ atom = <link rel="alternate" title="Atom feed" href="$(1)" \
195
195
  doc: .document $(ext)/unicorn_http.c NEWS ChangeLog
196
196
  for i in $(man1_rdoc); do echo > $$i; done
197
197
  find bin lib -type f -name '*.rbc' -exec rm -f '{}' ';'
198
- rdoc -a -t "$(shell sed -ne '1s/^= //p' README)"
198
+ rdoc -t "$(shell sed -ne '1s/^= //p' README)"
199
199
  install -m644 COPYING doc/COPYING
200
200
  install -m644 $(shell grep '^[A-Z]' .document) doc/
201
201
  $(MAKE) -C Documentation install-html install-man
@@ -63,7 +63,10 @@ before_fork do |server, worker|
63
63
  # end
64
64
  # end
65
65
  #
66
- # # *optionally* throttle the master from forking too quickly by sleeping
66
+ # Throttle the master from forking too quickly by sleeping. Due
67
+ # to the implementation of standard Unix signal handlers, this
68
+ # helps (but does not completely) prevent identical, repeated signals
69
+ # from being lost when the receiving process is busy.
67
70
  # sleep 1
68
71
  end
69
72
 
@@ -8,7 +8,9 @@ require 'logger'
8
8
  # example configuration files. An example config file for use with
9
9
  # nginx is also available at
10
10
  # http://unicorn.bogomips.org/examples/nginx.conf
11
- class Unicorn::Configurator < Struct.new(:set, :config_file, :after_reload)
11
+ class Unicorn::Configurator
12
+ attr_accessor :set, :config_file, :after_reload
13
+
12
14
  # :stopdoc:
13
15
  # used to stash stuff for deferred processing of cli options in
14
16
  # config.ru after "working_directory" is bound. Do not rely on
@@ -42,21 +44,24 @@ class Unicorn::Configurator < Struct.new(:set, :config_file, :after_reload)
42
44
 
43
45
  def initialize(defaults = {}) #:nodoc:
44
46
  self.set = Hash.new(:unset)
45
- use_defaults = defaults.delete(:use_defaults)
47
+ @use_defaults = defaults.delete(:use_defaults)
46
48
  self.config_file = defaults.delete(:config_file)
47
49
 
48
50
  # after_reload is only used by unicorn_rails, unsupported otherwise
49
51
  self.after_reload = defaults.delete(:after_reload)
50
52
 
51
- set.merge!(DEFAULTS) if use_defaults
52
- defaults.each { |key, value| self.send(key, value) }
53
+ set.merge!(DEFAULTS) if @use_defaults
54
+ defaults.each { |key, value| self.__send__(key, value) }
53
55
  Hash === set[:listener_opts] or
54
56
  set[:listener_opts] = Hash.new { |hash,key| hash[key] = {} }
55
57
  Array === set[:listeners] or set[:listeners] = []
56
- reload
58
+ reload(false)
57
59
  end
58
60
 
59
- def reload #:nodoc:
61
+ def reload(merge_defaults = true) #:nodoc:
62
+ if merge_defaults && @use_defaults
63
+ set.merge!(DEFAULTS) if @use_defaults
64
+ end
60
65
  instance_eval(File.read(config_file), config_file) if config_file
61
66
 
62
67
  parse_rackup_file
@@ -401,7 +406,10 @@ class Unicorn::Configurator < Struct.new(:set, :config_file, :after_reload)
401
406
 
402
407
  # sets the working directory for Unicorn. This ensures SIGUSR2 will
403
408
  # start a new instance of Unicorn in this directory. This may be
404
- # a symlink, a common scenario for Capistrano users.
409
+ # a symlink, a common scenario for Capistrano users. Unlike
410
+ # all other Unicorn configuration directives, this binds immediately
411
+ # for error checking and cannot be undone by unsetting it in the
412
+ # configuration file and reloading.
405
413
  def working_directory(path)
406
414
  # just let chdir raise errors
407
415
  path = File.expand_path(path)
data/lib/unicorn/const.rb CHANGED
@@ -7,8 +7,8 @@
7
7
  # improve things much compared to constants.
8
8
  module Unicorn::Const
9
9
 
10
- # The current version of Unicorn, currently 2.0.0pre3
11
- UNICORN_VERSION = "2.0.0pre3"
10
+ # The current version of Unicorn, currently 2.0.0
11
+ UNICORN_VERSION = "2.0.0"
12
12
 
13
13
  # default TCP listen host address (0.0.0.0, all interfaces)
14
14
  DEFAULT_HOST = "0.0.0.0"
@@ -50,6 +50,10 @@ class Unicorn::HttpServer
50
50
  # signal queue used for self-piping
51
51
  SIG_QUEUE = []
52
52
 
53
+ # list of signals we care about and trap in master.
54
+ QUEUE_SIGS = [ :WINCH, :QUIT, :INT, :TERM, :USR1, :USR2, :HUP, :TTIN, :TTOU ]
55
+
56
+ # :startdoc:
53
57
  # We populate this at startup so we can figure out how to reexecute
54
58
  # and upgrade the currently running instance of Unicorn
55
59
  # This Hash is considered a stable interface and changing its contents
@@ -82,7 +86,6 @@ class Unicorn::HttpServer
82
86
  }.call,
83
87
  0 => $0.dup,
84
88
  }
85
- # :startdoc:
86
89
 
87
90
  # Creates a working server on host:port (strange things happen if
88
91
  # port isn't a Number). Use HttpServer::run to start the server and
@@ -151,8 +154,8 @@ class Unicorn::HttpServer
151
154
  # setup signal handlers before writing pid file in case people get
152
155
  # trigger happy and send signals as soon as the pid file exists.
153
156
  # Note that signals don't actually get handled until the #join method
154
- QUEUE_SIGS.each { |sig| trap_deferred(sig) }
155
- trap(:CHLD) { |_| awaken_master }
157
+ QUEUE_SIGS.each { |sig| trap(sig) { SIG_QUEUE << sig; awaken_master } }
158
+ trap(:CHLD) { awaken_master }
156
159
  self.pid = config[:pid]
157
160
 
158
161
  self.master_pid = $$
@@ -287,14 +290,14 @@ class Unicorn::HttpServer
287
290
  when nil
288
291
  # avoid murdering workers after our master process (or the
289
292
  # machine) comes out of suspend/hibernation
290
- if (last_check + timeout) >= (last_check = Time.now)
291
- murder_lazy_workers
293
+ if (last_check + @timeout) >= (last_check = Time.now)
294
+ sleep_time = murder_lazy_workers
292
295
  else
293
296
  # wait for workers to wakeup on suspend
294
- master_sleep(timeout/2.0 + 1)
297
+ sleep_time = @timeout/2.0 + 1
295
298
  end
296
299
  maintain_worker_count if respawn
297
- master_sleep(1)
300
+ master_sleep(sleep_time)
298
301
  when :QUIT # graceful shutdown
299
302
  break
300
303
  when :TERM, :INT # immediate shutdown
@@ -354,24 +357,7 @@ class Unicorn::HttpServer
354
357
 
355
358
  private
356
359
 
357
- # list of signals we care about and trap in master.
358
- QUEUE_SIGS = [ :WINCH, :QUIT, :INT, :TERM, :USR1, :USR2, :HUP,
359
- :TTIN, :TTOU ]
360
-
361
- # defer a signal for later processing in #join (master process)
362
- def trap_deferred(signal)
363
- trap(signal) do |sig_nr|
364
- if SIG_QUEUE.size < 5
365
- SIG_QUEUE << signal
366
- awaken_master
367
- else
368
- logger.error "ignoring SIG#{signal}, queue=#{SIG_QUEUE.inspect}"
369
- end
370
- end
371
- end
372
-
373
360
  # wait for a signal hander to wake us up and then consume the pipe
374
- # Wake up every second anyways to run murder_lazy_workers
375
361
  def master_sleep(sec)
376
362
  IO.select([ SELF_PIPE[0] ], nil, nil, sec) or return
377
363
  SELF_PIPE[0].kgio_tryread(11)
@@ -457,15 +443,23 @@ class Unicorn::HttpServer
457
443
  # is stale for >timeout seconds, then we'll kill the corresponding
458
444
  # worker.
459
445
  def murder_lazy_workers
446
+ t = @timeout
447
+ next_sleep = 1
460
448
  WORKERS.dup.each_pair do |wpid, worker|
461
449
  stat = worker.tmp.stat
462
450
  # skip workers that disable fchmod or have never fchmod-ed
463
451
  stat.mode == 0100600 and next
464
- (diff = (Time.now - stat.ctime)) <= timeout and next
452
+ diff = Time.now - stat.ctime
453
+ if diff <= t
454
+ tmp = t - diff
455
+ next_sleep < tmp and next_sleep = tmp
456
+ next
457
+ end
465
458
  logger.error "worker=#{worker.nr} PID:#{wpid} timeout " \
466
- "(#{diff}s > #{timeout}s), killing"
459
+ "(#{diff}s > #{t}s), killing"
467
460
  kill_worker(:KILL, wpid) # take no prisoners for timeout violations
468
461
  end
462
+ next_sleep
469
463
  end
470
464
 
471
465
  def spawn_missing_workers
@@ -0,0 +1,82 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 9 "reloading unset config resets defaults"
4
+
5
+ t_begin "setup and start" && {
6
+ unicorn_setup
7
+ rtmpfiles unicorn_config_orig before_reload after_reload
8
+ cat $unicorn_config > $unicorn_config_orig
9
+ cat >> $unicorn_config <<EOF
10
+ logger Logger.new(STDOUT)
11
+ preload_app true
12
+ timeout 0x7fffffff
13
+ worker_processes 2
14
+ after_fork { |s,w| }
15
+ \$dump_cfg = lambda { |fp,srv|
16
+ defaults = Unicorn::Configurator::DEFAULTS
17
+ defaults.keys.map { |x| x.to_s }.sort.each do |key|
18
+ next if key =~ %r{\Astd(?:err|out)_path\z}
19
+ key = key.to_sym
20
+ def_value = defaults[key]
21
+ srv_value = srv.__send__(key)
22
+ fp << "#{key}|#{srv_value}|#{def_value}\\n"
23
+ end
24
+ }
25
+ before_fork { |s,w|
26
+ File.open("$before_reload", "a") { |fp| \$dump_cfg.call(fp, s) }
27
+ }
28
+ before_exec { |s| }
29
+ EOF
30
+ unicorn -D -c $unicorn_config env.ru
31
+ unicorn_wait_start
32
+ }
33
+
34
+ t_begin "ensure worker is started" && {
35
+ curl -sSf http://$listen/ > $tmp
36
+ }
37
+
38
+ t_begin "replace config file with original(-ish)" && {
39
+ grep -v ^pid < $unicorn_config_orig > $unicorn_config
40
+ cat >> $unicorn_config <<EOF
41
+ before_fork { |s,w|
42
+ File.open("$after_reload", "a") { |fp| \$dump_cfg.call(fp, s) }
43
+ }
44
+ EOF
45
+ }
46
+
47
+ t_begin "reload signal succeeds" && {
48
+ kill -HUP $unicorn_pid
49
+ while ! egrep '(done|error) reloading' $r_err >/dev/null
50
+ do
51
+ sleep 1
52
+ done
53
+
54
+ grep 'done reloading' $r_err >/dev/null
55
+ }
56
+
57
+ t_begin "ensure worker is started" && {
58
+ curl -sSf http://$listen/ > $tmp
59
+ }
60
+
61
+ t_begin "pid file no longer exists" && {
62
+ if test -f $pid
63
+ then
64
+ die "pid=$pid should not exist"
65
+ fi
66
+ }
67
+
68
+ t_begin "killing succeeds" && {
69
+ kill $unicorn_pid
70
+ }
71
+
72
+ t_begin "check stderr" && {
73
+ check_stderr
74
+ }
75
+
76
+ t_begin "ensure reloading restored settings" && {
77
+ awk < $after_reload -F'|' '
78
+ $1 != "before_fork" && $2 != $3 { print $0; exit(1) }
79
+ '
80
+ }
81
+
82
+ t_done
data/unicorn.gemspec CHANGED
@@ -36,7 +36,7 @@ Gem::Specification.new do |s|
36
36
  s.homepage = %q{http://unicorn.bogomips.org/}
37
37
 
38
38
  summary = %q{Rack HTTP server for fast clients and Unix}
39
- s.rdoc_options = [ "-Na", "-t", "Unicorn: #{summary}" ]
39
+ s.rdoc_options = [ "-t", "Unicorn: #{summary}" ]
40
40
  s.require_paths = %w(lib ext)
41
41
  s.rubyforge_project = %q{mongrel}
42
42
  s.summary = summary
@@ -50,7 +50,7 @@ Gem::Specification.new do |s|
50
50
  s.add_dependency(%q<rack>)
51
51
  s.add_dependency(%q<kgio>, '~> 1.3.1')
52
52
 
53
- s.add_development_dependency('isolate', '~> 2.1.2')
53
+ s.add_development_dependency('isolate', '~> 3.0.0')
54
54
 
55
55
  # s.licenses = %w(GPLv2 Ruby) # licenses= method is not in older RubyGems
56
56
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unicorn
3
3
  version: !ruby/object:Gem::Version
4
- hash: -766259860
5
- prerelease: true
4
+ hash: 15
5
+ prerelease: false
6
6
  segments:
7
7
  - 2
8
8
  - 0
9
- - 0pre3
10
- version: 2.0.0pre3
9
+ - 0
10
+ version: 2.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Unicorn hackers
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-09 00:00:00 +00:00
18
+ date: 2010-10-27 00:00:00 +00:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -56,12 +56,12 @@ dependencies:
56
56
  requirements:
57
57
  - - ~>
58
58
  - !ruby/object:Gem::Version
59
- hash: 15
59
+ hash: 7
60
60
  segments:
61
- - 2
62
- - 1
63
- - 2
64
- version: 2.1.2
61
+ - 3
62
+ - 0
63
+ - 0
64
+ version: 3.0.0
65
65
  type: :development
66
66
  version_requirements: *id003
67
67
  description: |-
@@ -240,6 +240,7 @@ files:
240
240
  - t/t0009-winch_ttin.sh
241
241
  - t/t0010-reap-logging.sh
242
242
  - t/t0011-active-unix-socket.sh
243
+ - t/t0012-reload-empty-config.sh
243
244
  - t/t0300-rails3-basic.sh
244
245
  - t/t0301-rails3-missing-config-ru.sh
245
246
  - t/t0302-rails3-alt-working_directory.sh
@@ -349,7 +350,6 @@ licenses: []
349
350
 
350
351
  post_install_message:
351
352
  rdoc_options:
352
- - -Na
353
353
  - -t
354
354
  - "Unicorn: Rack HTTP server for fast clients and Unix"
355
355
  require_paths:
@@ -367,14 +367,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
367
367
  required_rubygems_version: !ruby/object:Gem::Requirement
368
368
  none: false
369
369
  requirements:
370
- - - ">"
370
+ - - ">="
371
371
  - !ruby/object:Gem::Version
372
- hash: 25
372
+ hash: 3
373
373
  segments:
374
- - 1
375
- - 3
376
- - 1
377
- version: 1.3.1
374
+ - 0
375
+ version: "0"
378
376
  requirements: []
379
377
 
380
378
  rubyforge_project: mongrel