unicorn 4.7.0 → 4.8.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/GIT-VERSION-GEN +1 -1
- data/SIGNALS +11 -2
- data/lib/unicorn.rb +5 -0
- data/lib/unicorn/http_server.rb +47 -51
- data/lib/unicorn/stream_input.rb +1 -4
- data/lib/unicorn/worker.rb +64 -0
- data/t/t0300-no-default-middleware.sh +6 -1
- data/test/unit/test_socket_helper.rb +4 -2
- metadata +43 -88
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a2554354da992cb50d7fb537e1f0e71834d3a82c
|
4
|
+
data.tar.gz: 211ee8070608c0db6a605453061cb22059c92912
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0b9d4e9734fa2a501571e0ca97b36c9a9bef4b44985939bb3eaafac5dcbe473b8b38582cf2b076f0dcc2c2b19bc93ed0ee14934348d36483cb84f22d655fce21
|
7
|
+
data.tar.gz: 4b68dba9d31fb5352e4ee9e7b6313910f728a6293ab0c35c7944357ea6eef6c7870c502ec15b2df32c6618eb0ec5e0a3248bd8767447dbc9def526f9246cbc88
|
data/GIT-VERSION-GEN
CHANGED
data/SIGNALS
CHANGED
@@ -7,6 +7,9 @@ signal handling matches the behavior of {nginx}[http://nginx.net/] so it
|
|
7
7
|
should be possible to easily share process management scripts between
|
8
8
|
Unicorn and nginx.
|
9
9
|
|
10
|
+
One example init script is distributed with unicorn:
|
11
|
+
http://unicorn.bogomips.org/examples/init.sh
|
12
|
+
|
10
13
|
=== Master Process
|
11
14
|
|
12
15
|
* HUP - reloads config file and gracefully restart all workers.
|
@@ -42,6 +45,10 @@ Unicorn and nginx.
|
|
42
45
|
|
43
46
|
=== Worker Processes
|
44
47
|
|
48
|
+
Note: as of unicorn 4.8, the master uses a pipe to signal workers
|
49
|
+
instead of kill(2) for most cases. Using signals still (and works and
|
50
|
+
remains supported for external tools/libraries), however.
|
51
|
+
|
45
52
|
Sending signals directly to the worker processes should not normally be
|
46
53
|
needed. If the master process is running, any exited worker will be
|
47
54
|
automatically respawned.
|
@@ -49,6 +56,8 @@ automatically respawned.
|
|
49
56
|
* INT/TERM - Quick shutdown, immediately exit.
|
50
57
|
Unless WINCH has been sent to the master (or the master is killed),
|
51
58
|
the master process will respawn a worker to replace this one.
|
59
|
+
Immediate shutdown is still triggered using kill(2) and not the
|
60
|
+
internal pipe as of unicorn 4.8
|
52
61
|
|
53
62
|
* QUIT - Gracefully exit after finishing the current request.
|
54
63
|
Unless WINCH has been sent to the master (or the master is killed),
|
@@ -101,8 +110,8 @@ The procedure is exactly like that of nginx:
|
|
101
110
|
|
102
111
|
3. You can now send WINCH to the old master process so only the new workers
|
103
112
|
serve requests. If your unicorn process is bound to an interactive
|
104
|
-
terminal, you can skip this step. Step 5 will be more
|
105
|
-
you can also skip it if your process is not daemonized.
|
113
|
+
terminal (not daemonized), you can skip this step. Step 5 will be more
|
114
|
+
difficult but you can also skip it if your process is not daemonized.
|
106
115
|
|
107
116
|
4. You should now ensure that everything is running correctly with the
|
108
117
|
new workers as the old workers die off.
|
data/lib/unicorn.rb
CHANGED
@@ -97,6 +97,11 @@ module Unicorn
|
|
97
97
|
logger.error "#{prefix}: #{message} (#{exc.class})"
|
98
98
|
exc.backtrace.each { |line| logger.error(line) }
|
99
99
|
end
|
100
|
+
|
101
|
+
# remove this when we only support Ruby >= 2.0
|
102
|
+
def self.pipe # :nodoc:
|
103
|
+
Kgio::Pipe.new.each { |io| io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) }
|
104
|
+
end
|
100
105
|
# :startdoc:
|
101
106
|
end
|
102
107
|
# :enddoc:
|
data/lib/unicorn/http_server.rb
CHANGED
@@ -42,16 +42,8 @@ class Unicorn::HttpServer
|
|
42
42
|
# it to wake up the master from IO.select in exactly the same manner
|
43
43
|
# djb describes in http://cr.yp.to/docs/selfpipe.html
|
44
44
|
#
|
45
|
-
# * The workers immediately close the pipe they inherit
|
46
|
-
#
|
47
|
-
# pipe is also used to wakeup from IO.select from inside (worker)
|
48
|
-
# signal handlers. However, workers *close* the pipe descriptors in
|
49
|
-
# the signal handlers to raise EBADF in IO.select instead of writing
|
50
|
-
# like we do in the master. We cannot easily use the reader set for
|
51
|
-
# IO.select because LISTENERS is already that set, and it's extra
|
52
|
-
# work (and cycles) to distinguish the pipe FD from the reader set
|
53
|
-
# once IO.select returns. So we're lazy and just close the pipe when
|
54
|
-
# a (rare) signal arrives in the worker and reinitialize the pipe later.
|
45
|
+
# * The workers immediately close the pipe they inherit. See the
|
46
|
+
# Unicorn::Worker class for the pipe workers use.
|
55
47
|
SELF_PIPE = []
|
56
48
|
|
57
49
|
# signal queue used for self-piping
|
@@ -127,7 +119,7 @@ class Unicorn::HttpServer
|
|
127
119
|
inherit_listeners!
|
128
120
|
# this pipe is used to wake us up from select(2) in #join when signals
|
129
121
|
# are trapped. See trap_deferred.
|
130
|
-
|
122
|
+
SELF_PIPE.replace(Unicorn.pipe)
|
131
123
|
|
132
124
|
# setup signal handlers before writing pid file in case people get
|
133
125
|
# trigger happy and send signals as soon as the pid file exists.
|
@@ -136,20 +128,15 @@ class Unicorn::HttpServer
|
|
136
128
|
trap(:CHLD) { awaken_master }
|
137
129
|
|
138
130
|
# write pid early for Mongrel compatibility if we're not inheriting sockets
|
139
|
-
# This
|
140
|
-
#
|
141
|
-
#
|
142
|
-
self.pid = config[:pid]
|
131
|
+
# This is needed for compatibility some Monit setups at least.
|
132
|
+
# This unfortunately has the side effect of clobbering valid PID if
|
133
|
+
# we upgrade and the upgrade breaks during preload_app==true && build_app!
|
134
|
+
self.pid = config[:pid]
|
143
135
|
|
144
136
|
self.master_pid = $$
|
145
137
|
build_app! if preload_app
|
146
138
|
bind_new_listeners!
|
147
139
|
|
148
|
-
# Assuming preload_app==false, we drop the pid file after the app is ready
|
149
|
-
# to process requests. If binding or build_app! fails with
|
150
|
-
# preload_app==true, we'll never get here and the parent will recover
|
151
|
-
self.pid = config[:pid] if ENV["UNICORN_FD"]
|
152
|
-
|
153
140
|
spawn_missing_workers
|
154
141
|
self
|
155
142
|
end
|
@@ -311,14 +298,14 @@ class Unicorn::HttpServer
|
|
311
298
|
logger.info "master reopening logs..."
|
312
299
|
Unicorn::Util.reopen_logs
|
313
300
|
logger.info "master done reopening logs"
|
314
|
-
|
301
|
+
soft_kill_each_worker(:USR1)
|
315
302
|
when :USR2 # exec binary, stay alive in case something went wrong
|
316
303
|
reexec
|
317
304
|
when :WINCH
|
318
305
|
if Unicorn::Configurator::RACKUP[:daemonized]
|
319
306
|
respawn = false
|
320
307
|
logger.info "gracefully stopping all workers"
|
321
|
-
|
308
|
+
soft_kill_each_worker(:QUIT)
|
322
309
|
self.worker_processes = 0
|
323
310
|
else
|
324
311
|
logger.info "SIGWINCH ignored because we're not daemonized"
|
@@ -350,7 +337,11 @@ class Unicorn::HttpServer
|
|
350
337
|
self.listeners = []
|
351
338
|
limit = Time.now + timeout
|
352
339
|
until WORKERS.empty? || Time.now > limit
|
353
|
-
|
340
|
+
if graceful
|
341
|
+
soft_kill_each_worker(:QUIT)
|
342
|
+
else
|
343
|
+
kill_each_worker(:TERM)
|
344
|
+
end
|
354
345
|
sleep(0.1)
|
355
346
|
reap_all_workers
|
356
347
|
end
|
@@ -503,6 +494,7 @@ class Unicorn::HttpServer
|
|
503
494
|
end
|
504
495
|
|
505
496
|
def after_fork_internal
|
497
|
+
SELF_PIPE.each { |io| io.close }.clear # this is master-only, now
|
506
498
|
@ready_pipe.close if @ready_pipe
|
507
499
|
Unicorn::Configurator::RACKUP.clear
|
508
500
|
@ready_pipe = @init_listeners = @before_exec = @before_fork = nil
|
@@ -522,6 +514,7 @@ class Unicorn::HttpServer
|
|
522
514
|
before_fork.call(self, worker)
|
523
515
|
if pid = fork
|
524
516
|
WORKERS[pid] = worker
|
517
|
+
worker.atfork_parent
|
525
518
|
else
|
526
519
|
after_fork_internal
|
527
520
|
worker_loop(worker)
|
@@ -536,9 +529,7 @@ class Unicorn::HttpServer
|
|
536
529
|
def maintain_worker_count
|
537
530
|
(off = WORKERS.size - worker_processes) == 0 and return
|
538
531
|
off < 0 and return spawn_missing_workers
|
539
|
-
WORKERS.
|
540
|
-
w.nr >= worker_processes and kill_worker(:QUIT, wpid) rescue nil
|
541
|
-
}
|
532
|
+
WORKERS.each_value { |w| w.nr >= worker_processes and w.soft_kill(:QUIT) }
|
542
533
|
end
|
543
534
|
|
544
535
|
# if we get any error, try to write something back to the client
|
@@ -605,6 +596,7 @@ class Unicorn::HttpServer
|
|
605
596
|
# traps for USR1, USR2, and HUP may be set in the after_fork Proc
|
606
597
|
# by the user.
|
607
598
|
def init_worker_process(worker)
|
599
|
+
worker.atfork_child
|
608
600
|
# we'll re-trap :QUIT later for graceful shutdown iff we accept clients
|
609
601
|
EXIT_SIGS.each { |sig| trap(sig) { exit!(0) } }
|
610
602
|
exit!(0) if (SIG_QUEUE & EXIT_SIGS)[0]
|
@@ -613,23 +605,27 @@ class Unicorn::HttpServer
|
|
613
605
|
SIG_QUEUE.clear
|
614
606
|
proc_name "worker[#{worker.nr}]"
|
615
607
|
START_CTX.clear
|
616
|
-
init_self_pipe!
|
617
608
|
WORKERS.clear
|
609
|
+
|
610
|
+
after_fork.call(self, worker) # can drop perms and create listeners
|
618
611
|
LISTENERS.each { |sock| sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) }
|
619
|
-
|
612
|
+
|
620
613
|
worker.user(*user) if user.kind_of?(Array) && ! worker.switched
|
621
614
|
self.timeout /= 2.0 # halve it for select()
|
622
615
|
@config = nil
|
623
616
|
build_app! unless preload_app
|
624
617
|
ssl_enable!
|
625
618
|
@after_fork = @listener_opts = @orig_app = nil
|
619
|
+
readers = LISTENERS.dup
|
620
|
+
readers << worker
|
621
|
+
trap(:QUIT) { readers.each { |io| io.close }.replace([false]) }
|
622
|
+
readers
|
626
623
|
end
|
627
624
|
|
628
625
|
def reopen_worker_logs(worker_nr)
|
629
626
|
logger.info "worker=#{worker_nr} reopening logs..."
|
630
627
|
Unicorn::Util.reopen_logs
|
631
628
|
logger.info "worker=#{worker_nr} done reopening logs"
|
632
|
-
init_self_pipe!
|
633
629
|
rescue => e
|
634
630
|
logger.error(e) rescue nil
|
635
631
|
exit!(77) # EX_NOPERM in sysexits.h
|
@@ -640,22 +636,24 @@ class Unicorn::HttpServer
|
|
640
636
|
# given a INT, QUIT, or TERM signal)
|
641
637
|
def worker_loop(worker)
|
642
638
|
ppid = master_pid
|
643
|
-
init_worker_process(worker)
|
639
|
+
readers = init_worker_process(worker)
|
644
640
|
nr = 0 # this becomes negative if we need to reopen logs
|
645
|
-
l = LISTENERS.dup
|
646
|
-
ready = l.dup
|
647
641
|
|
648
|
-
#
|
649
|
-
|
650
|
-
trap(:
|
651
|
-
|
642
|
+
# this only works immediately if the master sent us the signal
|
643
|
+
# (which is the normal case)
|
644
|
+
trap(:USR1) { nr = -65536 }
|
645
|
+
|
646
|
+
ready = readers.dup
|
647
|
+
@logger.info "worker=#{worker.nr} ready"
|
652
648
|
|
653
649
|
begin
|
654
650
|
nr < 0 and reopen_worker_logs(worker.nr)
|
655
651
|
nr = 0
|
656
|
-
|
657
652
|
worker.tick = Time.now.to_i
|
658
|
-
|
653
|
+
tmp = ready.dup
|
654
|
+
while sock = tmp.shift
|
655
|
+
# Unicorn::Worker#kgio_tryaccept is not like accept(2) at all,
|
656
|
+
# but that will return false
|
659
657
|
if client = sock.kgio_tryaccept
|
660
658
|
process_client(client)
|
661
659
|
nr += 1
|
@@ -668,8 +666,8 @@ class Unicorn::HttpServer
|
|
668
666
|
# we're probably reasonably busy, so avoid calling select()
|
669
667
|
# and do a speculative non-blocking accept() on ready listeners
|
670
668
|
# before we sleep again in select().
|
671
|
-
unless nr == 0
|
672
|
-
|
669
|
+
unless nr == 0
|
670
|
+
tmp = ready.dup
|
673
671
|
redo
|
674
672
|
end
|
675
673
|
|
@@ -677,11 +675,11 @@ class Unicorn::HttpServer
|
|
677
675
|
|
678
676
|
# timeout used so we can detect parent death:
|
679
677
|
worker.tick = Time.now.to_i
|
680
|
-
ret = IO.select(
|
678
|
+
ret = IO.select(readers, nil, nil, @timeout) and ready = ret[0]
|
681
679
|
rescue => e
|
682
|
-
redo if nr < 0
|
683
|
-
Unicorn.log_error(@logger, "listen loop error", e) if
|
684
|
-
end while
|
680
|
+
redo if nr < 0
|
681
|
+
Unicorn.log_error(@logger, "listen loop error", e) if readers[0]
|
682
|
+
end while readers[0]
|
685
683
|
end
|
686
684
|
|
687
685
|
# delivers a signal to a worker and fails gracefully if the worker
|
@@ -697,6 +695,10 @@ class Unicorn::HttpServer
|
|
697
695
|
WORKERS.keys.each { |wpid| kill_worker(signal, wpid) }
|
698
696
|
end
|
699
697
|
|
698
|
+
def soft_kill_each_worker(signal)
|
699
|
+
WORKERS.each_value { |worker| worker.soft_kill(signal) }
|
700
|
+
end
|
701
|
+
|
700
702
|
# unlinks a PID file at given +path+ if it contains the current PID
|
701
703
|
# still potentially racy without locking the directory (which is
|
702
704
|
# non-portable and may interact badly with other programs), but the
|
@@ -725,7 +727,7 @@ class Unicorn::HttpServer
|
|
725
727
|
config[:listeners].replace(@init_listeners)
|
726
728
|
config.reload
|
727
729
|
config.commit!(self)
|
728
|
-
|
730
|
+
soft_kill_each_worker(:QUIT)
|
729
731
|
Unicorn::Util.reopen_logs
|
730
732
|
self.app = orig_app
|
731
733
|
build_app! if preload_app
|
@@ -761,12 +763,6 @@ class Unicorn::HttpServer
|
|
761
763
|
io.sync = true
|
762
764
|
end
|
763
765
|
|
764
|
-
def init_self_pipe!
|
765
|
-
SELF_PIPE.each { |io| io.close rescue nil }
|
766
|
-
SELF_PIPE.replace(Kgio::Pipe.new)
|
767
|
-
SELF_PIPE.each { |io| io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) }
|
768
|
-
end
|
769
|
-
|
770
766
|
def inherit_listeners!
|
771
767
|
# inherit sockets from parents, they need to be plain Socket objects
|
772
768
|
# before they become Kgio::UNIXServer or Kgio::TCPServer
|
data/lib/unicorn/stream_input.rb
CHANGED
@@ -139,10 +139,7 @@ private
|
|
139
139
|
# we do support clients that shutdown(SHUT_WR) after the
|
140
140
|
# _entire_ request has been sent, and those will not have
|
141
141
|
# raised EOFError on us.
|
142
|
-
if @socket
|
143
|
-
@socket.shutdown
|
144
|
-
@socket.close
|
145
|
-
end
|
142
|
+
@socket.shutdown if @socket
|
146
143
|
ensure
|
147
144
|
raise Unicorn::ClientShutdown, "bytes_read=#{@bytes_read}", []
|
148
145
|
end
|
data/lib/unicorn/worker.rb
CHANGED
@@ -12,6 +12,7 @@ class Unicorn::Worker
|
|
12
12
|
# :stopdoc:
|
13
13
|
attr_accessor :nr, :switched
|
14
14
|
attr_writer :tmp
|
15
|
+
attr_reader :to_io # IO.select-compatible
|
15
16
|
|
16
17
|
PER_DROP = Raindrops::PAGE_SIZE / Raindrops::SIZE
|
17
18
|
DROPS = []
|
@@ -23,6 +24,66 @@ class Unicorn::Worker
|
|
23
24
|
@raindrop[@offset] = 0
|
24
25
|
@nr = nr
|
25
26
|
@tmp = @switched = false
|
27
|
+
@to_io, @master = Unicorn.pipe
|
28
|
+
end
|
29
|
+
|
30
|
+
def atfork_child # :nodoc:
|
31
|
+
# we _must_ close in child, parent just holds this open to signal
|
32
|
+
@master = @master.close
|
33
|
+
end
|
34
|
+
|
35
|
+
# master fakes SIGQUIT using this
|
36
|
+
def quit # :nodoc:
|
37
|
+
@master = @master.close if @master
|
38
|
+
end
|
39
|
+
|
40
|
+
# parent does not read
|
41
|
+
def atfork_parent # :nodoc:
|
42
|
+
@to_io = @to_io.close
|
43
|
+
end
|
44
|
+
|
45
|
+
# call a signal handler immediately without triggering EINTR
|
46
|
+
# We do not use the more obvious Process.kill(sig, $$) here since
|
47
|
+
# that signal delivery may be deferred. We want to avoid signal delivery
|
48
|
+
# while the Rack app.call is running because some database drivers
|
49
|
+
# (e.g. ruby-pg) may cancel pending requests.
|
50
|
+
def fake_sig(sig) # :nodoc:
|
51
|
+
old_cb = trap(sig, "IGNORE")
|
52
|
+
old_cb.call
|
53
|
+
ensure
|
54
|
+
trap(sig, old_cb)
|
55
|
+
end
|
56
|
+
|
57
|
+
# master sends fake signals to children
|
58
|
+
def soft_kill(sig) # :nodoc:
|
59
|
+
case sig
|
60
|
+
when Integer
|
61
|
+
signum = sig
|
62
|
+
else
|
63
|
+
signum = Signal.list[sig.to_s] or
|
64
|
+
raise ArgumentError, "BUG: bad signal: #{sig.inspect}"
|
65
|
+
end
|
66
|
+
# writing and reading 4 bytes on a pipe is atomic on all POSIX platforms
|
67
|
+
# Do not care in the odd case the buffer is full, here.
|
68
|
+
@master.kgio_trywrite([signum].pack('l'))
|
69
|
+
rescue Errno::EPIPE
|
70
|
+
# worker will be reaped soon
|
71
|
+
end
|
72
|
+
|
73
|
+
# this only runs when the Rack app.call is not running
|
74
|
+
# act like a listener
|
75
|
+
def kgio_tryaccept # :nodoc:
|
76
|
+
case buf = @to_io.kgio_tryread(4)
|
77
|
+
when String
|
78
|
+
# unpack the buffer and trigger the signal handler
|
79
|
+
signum = buf.unpack('l')
|
80
|
+
fake_sig(signum[0])
|
81
|
+
# keep looping, more signals may be queued
|
82
|
+
when nil # EOF: master died, but we are at a safe place to exit
|
83
|
+
fake_sig(:QUIT)
|
84
|
+
when :wait_readable # keep waiting
|
85
|
+
return false
|
86
|
+
end while true # loop, as multiple signals may be sent
|
26
87
|
end
|
27
88
|
|
28
89
|
# worker objects may be compared to just plain Integers
|
@@ -49,8 +110,11 @@ class Unicorn::Worker
|
|
49
110
|
end
|
50
111
|
end
|
51
112
|
|
113
|
+
# called in both the master (reaping worker) and worker (SIGQUIT handler)
|
52
114
|
def close # :nodoc:
|
53
115
|
@tmp.close if @tmp
|
116
|
+
@master.close if @master
|
117
|
+
@to_io.close if @to_io
|
54
118
|
end
|
55
119
|
|
56
120
|
# :startdoc:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/bin/sh
|
2
2
|
. ./test-lib.sh
|
3
|
-
t_plan
|
3
|
+
t_plan 3 "test the -N / --no-default-middleware option"
|
4
4
|
|
5
5
|
t_begin "setup and start" && {
|
6
6
|
unicorn_setup
|
@@ -12,4 +12,9 @@ t_begin "check exit status with Rack::Lint not present" && {
|
|
12
12
|
test 42 -eq "$(curl -sf -o/dev/null -w'%{http_code}' http://$listen/)"
|
13
13
|
}
|
14
14
|
|
15
|
+
t_begin "killing succeeds" && {
|
16
|
+
kill $unicorn_pid
|
17
|
+
check_stderr
|
18
|
+
}
|
19
|
+
|
15
20
|
t_done
|
@@ -190,6 +190,8 @@ class TestSocketHelper < Test::Unit::TestCase
|
|
190
190
|
name = "#@test_addr:#{port}"
|
191
191
|
sock = bind_listen(name, :reuseport => true)
|
192
192
|
cur = sock.getsockopt(Socket::SOL_SOCKET, SO_REUSEPORT).unpack('i')[0]
|
193
|
-
|
194
|
-
|
193
|
+
assert_operator cur, :>, 0
|
194
|
+
rescue Errno::ENOPROTOOPT
|
195
|
+
# kernel does not support SO_REUSEPORT (older Linux)
|
196
|
+
end
|
195
197
|
end
|
metadata
CHANGED
@@ -1,138 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
name:
|
3
|
-
dW5pY29ybg==
|
2
|
+
name: unicorn
|
4
3
|
version: !ruby/object:Gem::Version
|
5
|
-
version: 4.
|
6
|
-
prerelease:
|
4
|
+
version: 4.8.0.pre1
|
7
5
|
platform: ruby
|
8
6
|
authors:
|
9
7
|
- Unicorn hackers
|
10
8
|
autorequire:
|
11
9
|
bindir: bin
|
12
10
|
cert_chain: []
|
13
|
-
date: 2013-
|
11
|
+
date: 2013-12-09 00:00:00.000000000 Z
|
14
12
|
dependencies:
|
15
13
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
17
|
-
cmFjaw==
|
14
|
+
name: rack
|
18
15
|
requirement: !ruby/object:Gem::Requirement
|
19
|
-
none: false
|
20
16
|
requirements:
|
21
|
-
- -
|
17
|
+
- - '>='
|
22
18
|
- !ruby/object:Gem::Version
|
23
19
|
version: '0'
|
24
20
|
type: :runtime
|
25
21
|
prerelease: false
|
26
22
|
version_requirements: !ruby/object:Gem::Requirement
|
27
|
-
none: false
|
28
23
|
requirements:
|
29
|
-
- -
|
24
|
+
- - '>='
|
30
25
|
- !ruby/object:Gem::Version
|
31
26
|
version: '0'
|
32
27
|
- !ruby/object:Gem::Dependency
|
33
|
-
name:
|
34
|
-
a2dpbw==
|
28
|
+
name: kgio
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
36
|
-
none: false
|
37
30
|
requirements:
|
38
|
-
- -
|
39
|
-
fj4=
|
31
|
+
- - ~>
|
40
32
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
42
|
-
Mi42
|
33
|
+
version: '2.6'
|
43
34
|
type: :runtime
|
44
35
|
prerelease: false
|
45
36
|
version_requirements: !ruby/object:Gem::Requirement
|
46
|
-
none: false
|
47
37
|
requirements:
|
48
|
-
- -
|
49
|
-
fj4=
|
38
|
+
- - ~>
|
50
39
|
- !ruby/object:Gem::Version
|
51
|
-
version:
|
52
|
-
Mi42
|
40
|
+
version: '2.6'
|
53
41
|
- !ruby/object:Gem::Dependency
|
54
|
-
name:
|
55
|
-
cmFpbmRyb3Bz
|
42
|
+
name: raindrops
|
56
43
|
requirement: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
44
|
requirements:
|
59
|
-
- -
|
60
|
-
fj4=
|
45
|
+
- - ~>
|
61
46
|
- !ruby/object:Gem::Version
|
62
|
-
version:
|
63
|
-
MC43
|
47
|
+
version: '0.7'
|
64
48
|
type: :runtime
|
65
49
|
prerelease: false
|
66
50
|
version_requirements: !ruby/object:Gem::Requirement
|
67
|
-
none: false
|
68
51
|
requirements:
|
69
|
-
- -
|
70
|
-
fj4=
|
52
|
+
- - ~>
|
71
53
|
- !ruby/object:Gem::Version
|
72
|
-
version:
|
73
|
-
MC43
|
54
|
+
version: '0.7'
|
74
55
|
- !ruby/object:Gem::Dependency
|
75
|
-
name:
|
76
|
-
aXNvbGF0ZQ==
|
56
|
+
name: isolate
|
77
57
|
requirement: !ruby/object:Gem::Requirement
|
78
|
-
none: false
|
79
58
|
requirements:
|
80
|
-
- -
|
81
|
-
fj4=
|
59
|
+
- - ~>
|
82
60
|
- !ruby/object:Gem::Version
|
83
|
-
version:
|
84
|
-
My4y
|
61
|
+
version: '3.2'
|
85
62
|
type: :development
|
86
63
|
prerelease: false
|
87
64
|
version_requirements: !ruby/object:Gem::Requirement
|
88
|
-
none: false
|
89
65
|
requirements:
|
90
|
-
- -
|
91
|
-
fj4=
|
66
|
+
- - ~>
|
92
67
|
- !ruby/object:Gem::Version
|
93
|
-
version:
|
94
|
-
My4y
|
68
|
+
version: '3.2'
|
95
69
|
- !ruby/object:Gem::Dependency
|
96
|
-
name:
|
97
|
-
d3Jvbmdkb2M=
|
70
|
+
name: wrongdoc
|
98
71
|
requirement: !ruby/object:Gem::Requirement
|
99
|
-
none: false
|
100
72
|
requirements:
|
101
|
-
- -
|
102
|
-
fj4=
|
73
|
+
- - ~>
|
103
74
|
- !ruby/object:Gem::Version
|
104
|
-
version:
|
105
|
-
MS42LjE=
|
75
|
+
version: 1.6.1
|
106
76
|
type: :development
|
107
77
|
prerelease: false
|
108
78
|
version_requirements: !ruby/object:Gem::Requirement
|
109
|
-
none: false
|
110
79
|
requirements:
|
111
|
-
- -
|
112
|
-
fj4=
|
80
|
+
- - ~>
|
113
81
|
- !ruby/object:Gem::Version
|
114
|
-
version:
|
115
|
-
|
116
|
-
|
117
|
-
serve
|
118
|
-
|
82
|
+
version: 1.6.1
|
83
|
+
description: |-
|
84
|
+
\Unicorn is an HTTP server for Rack applications designed to only serve
|
119
85
|
fast clients on low-latency, high-bandwidth connections and take
|
120
|
-
|
121
86
|
advantage of features in Unix/Unix-like kernels. Slow clients should
|
122
|
-
|
123
87
|
only be served by placing a reverse proxy capable of fully buffering
|
124
|
-
|
125
|
-
|
126
|
-
email: !binary |-
|
127
|
-
bW9uZ3JlbC11bmljb3JuQHJ1Ynlmb3JnZS5vcmc=
|
88
|
+
both the the request and response in between \Unicorn and slow clients.
|
89
|
+
email: mongrel-unicorn@rubyforge.org
|
128
90
|
executables:
|
129
|
-
-
|
130
|
-
|
131
|
-
- !binary |-
|
132
|
-
dW5pY29ybl9yYWlscw==
|
91
|
+
- unicorn
|
92
|
+
- unicorn_rails
|
133
93
|
extensions:
|
134
|
-
-
|
135
|
-
ZXh0L3VuaWNvcm5faHR0cC9leHRjb25mLnJi
|
94
|
+
- ext/unicorn_http/extconf.rb
|
136
95
|
extra_rdoc_files:
|
137
96
|
- FAQ
|
138
97
|
- README
|
@@ -330,36 +289,32 @@ files:
|
|
330
289
|
- unicorn.gemspec
|
331
290
|
homepage: http://unicorn.bogomips.org/
|
332
291
|
licenses:
|
333
|
-
-
|
334
|
-
|
335
|
-
|
336
|
-
UnVieSAxLjg=
|
292
|
+
- GPLv2+
|
293
|
+
- Ruby 1.8
|
294
|
+
metadata: {}
|
337
295
|
post_install_message:
|
338
296
|
rdoc_options:
|
339
297
|
- -t
|
340
|
-
-
|
298
|
+
- 'Unicorn: Rack HTTP server for fast clients and Unix'
|
341
299
|
- -W
|
342
300
|
- http://bogomips.org/unicorn.git/tree/%s
|
343
301
|
require_paths:
|
344
302
|
- lib
|
345
303
|
required_ruby_version: !ruby/object:Gem::Requirement
|
346
|
-
none: false
|
347
304
|
requirements:
|
348
|
-
- -
|
305
|
+
- - '>='
|
349
306
|
- !ruby/object:Gem::Version
|
350
307
|
version: '0'
|
351
308
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
352
|
-
none: false
|
353
309
|
requirements:
|
354
|
-
- -
|
310
|
+
- - '>'
|
355
311
|
- !ruby/object:Gem::Version
|
356
|
-
version:
|
312
|
+
version: 1.3.1
|
357
313
|
requirements: []
|
358
|
-
rubyforge_project:
|
359
|
-
|
360
|
-
rubygems_version: 1.8.23
|
314
|
+
rubyforge_project: mongrel
|
315
|
+
rubygems_version: 2.1.9
|
361
316
|
signing_key:
|
362
|
-
specification_version:
|
317
|
+
specification_version: 4
|
363
318
|
summary: Rack HTTP server for fast clients and Unix
|
364
319
|
test_files:
|
365
320
|
- test/unit/test_configurator.rb
|