unicorn 2.0.0pre3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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