Date | Commit message (Collapse) |
|
This is only supported when SIGUSR1 is sent only to the master
process (which then resends SIGUSR1 to the workers).
Since we only added support for user/group switching in the
workers, we now chown any log files upon switching users so the
master can pick up and chown the log files later on. Thus
we can avoid having to restart workers because they fail to
rotate log files on their own.
|
|
Leaving the EOFError exception as-is bad because most
applications/frameworks run an application-wide exception
handler to pretty-print and/or log the exception with a huge
backtrace.
Since there's absolutely nothing we can do in the server-side
app to deal with clients prematurely shutting down, having a
backtrace does not make sense. Having a backtrace can even be
harmful since it creates unnecessary noise for application
engineers monitoring or tracking down real bugs.
|
|
This will benefit users of a copy-on-write-friendly memory
manager provided with Ruby Enterprise Edition. Additionally,
this will the reduce maintenance impact on Rainbows! in the future
since load/require are not thread-safe under 1.9.
|
|
Sometimes app loads and after_fork hooks can take a long time,
even longer than shorter timeouts. Since timeouts are only
meant for application processing when clients are involved,
we won't nuke workers that have never chmodded before.
|
|
Constant scoping appears to be a bit different under 1.9
|
|
This must be called in the after_fork hook because there may be
Ruby modules that'll allow things such as CPU affinity and
scheduling class/priority to be set on a per-worker basis. So
we give the user the ability to change users at any time during
the after_fork hook.
|
|
Even if START_CTX[:cwd] is pointing to another directory,
avoid overriding the user's decision to Dir.chdir if they
do it in either the Unicorn config file or the config.ru.
|
|
split out uncommon code from the common path
|
|
`sh -c pwd` doesn't reliably read ENV["PWD"] on all platforms,
this means that directories that are symlinks may be ignored
and the real path is resolved. This can be problematic when
doing upgrades for common deployment systems such as Capistrano
which rely on the working directory being a symlink.
|
|
If fstat() fails on an open file descriptor in the master,
something is seriously wrong (like your kernel is broken/buggy)
and trying to restart the worker that owned that file descriptor
is likely masking the symptoms. Instead let the error propagate
up to the main loop to avoid wasting cycles to restart broken
workers.
|
|
The method introduced in commit
6c8a3d3c55997978bacaecc5dbbb7d03c2fee345 to avoid killing
workers after suspend/hibernate interacted badly with the change
for OpenBSD fchmod(2) compatibility introduced with the 0.93.3
release. This interaction lead to workers with files stuck in
the zero state to never be murdered off for timeout violations.
Additionally, the method to avoid killing processes off was
never completely reliable and has been reworked even if we
entered suspend/hibernate/STOP during client processing.
This regression was discovered during continued development of the
Rainbows! test suite (which we will bring over as it becomes ready).
|
|
Since our :QUIT and :TERM signal handlers are idempotent, we can
safely retry sending signals in case workers don't/can't handle
them them the first time around. This appears to be a problem
with the Thread-based concurrency models in Rainbows! not
behaving well (no surprise, though, since pthreads and signals
are difficult to manage/mix properly).
|
|
This removes the Time.now.to_i comparison that was used to avoid
multiple, no-op fchmod() syscalls[1] within the same second.
This should allow us to run on OpenBSD where it can raise EINVAL
when Time.now.to_i is passed to it.
Reported-by: Jeremy Evans <jeremyevans0@gmail.com>
[1] - gettimeofday() from Time.now is not a real syscall on
VDSO-enabled x86_64 GNU/Linux systems where Unicorn is primarily
developed.
|
|
There seems to be a small amount of confusion regarding how it's
used (and some of the code is not very obvious). So explain our
usage of it and distinguish its use in the master vs worker(s).
|
|
Modifying this can be useful for esoteric cases like switching
entire Ruby installations or if the app was originally started
in a no-longer-existent directory and we can't upgrade because
we can't chdir to it.
|
|
There's always been a small window of opportunity for a script
to do File.read(pid).to_i would cause File.read() to read an
empty file and return "". This closes that window while
hopefully retaining backwards compatibility...
We've always checked for dirname(pid) writability in
Configurator, so we can safely write to a temporary file in the
intended directory and then atomically rename() it to the
destination path.
|
|
It's pointless to try and stat a file before trying to read it.
Instead just try opening it and rescue ENOENT because it
would've been racy anyways.
Additionally add some comments to keep us from forgetting
why we did the things we did with the pid file management.
|
|
I'd rather document and maintain a stable interface for the
Worker class than to have to deal with potential (portability
and security) issues with with supporting user privilege
management right now.
There's already an example of user/group-switching support in
the after_fork() hook and the error handling involved may be
different depending on the application and environment so I
remain hesitant to add official support for it...
|
|
It's compatible with both Ruby 1.8 and 1.9 without
needing a Range object.
|
|
Sometimes the upgraded version won't survive and we can fail to
unset that pid and instead accidentally create a local variable.
This is unlikely to be a problem in practice because this
variable is immediately reclobbered when we fork.
|
|
We've started using magic comments to ensure any strings we
create are binary instead. Additionally, ensure we create any
StringIO objects with an explicit string (which default to
binary) to ensure the StringIO object is binary. This is
because StringIO.new (with no arguments) will always use the
process-wide default encoding since it does not know about
magic comments (and couldn't, really...)
|
|
This may be redundant for the "normal" configuration file
directive, but allows the same syntax to be used in after_fork
hooks where HttpServer#listen() may be called.
|
|
This allows per-worker listeners to be configured to retry and
and not continue until the equivalent worker belonging to a
previous master (or even another server) has released the
socket.
In the Configurator RDoc, include better examples for
per-worker server.listen calls using these :tries == -1.
Inspired by an example by Chris Wanstrath.
|
|
When SIGHUP reloads the config, we didn't account for the case
where the listen socket was completely unspecified. Thus the
default listener (0.0.0.0:8080), did not get preserved and
re-injected into the config properly.
Note that relying on the default listen or specifying listeners
on the command-line means it's /practically/ impossible to
_unbind_ those listeners with a configuration file reload. We
also need to preserve the (unspecified) default listener across
upgrades that later result in SIGHUP, too; so the easiest way is
to inject the default listener into the command-line for
upgrades.
Many thanks to James Golick for reporting and helping me track
down the bug since this behavior is difficult to write reliable
automated tests for.
Signed-off-by: Eric Wong <normalperson@yhbt.net>
|
|
This gives applications more rope to play with in case they have
any reasons for changing some values of the default constants.
Freezing strings for Hash assignments still speeds up MRI, so
we'll keep on doing that for now (and as long as MRI supports
frozen strings, I expect them to always be faster for Hashes
though I'd be very happy to be proven wrong...)
|
|
We used to try it on every listener, but then rarely-used
listener ports used mainly for monitoring/debugging would have
accept() unnecessary called, getting unnecessarily expensive
inside the kernel.
|
|
This ensures any string literals that pop up in *our* code will
just be a bag of bytes. This shouldn't affect/fix/break
existing apps in most cases, but most constants will always have
the "correct" encoding (none!) to be consistent with HTTP/socket
expectations. Since this comment affects things only on a
per-source basis, it won't affect existing apps with the
exception of strings we pass to the Rack application.
This will eventually allow us to get rid of that Unicorn::Z
constant, too.
|
|
Avoid potential issues that can arise from logging any weird
characters that may not be supported in the current encoding.
|
|
HTTP/0.9 GET requests expect responses without headers. Some
weird applications/tools still use the ancient HTTP/0.9
protocol for weird reasons, so we'll support them.
ref: rfc 1945, section 4.1
|
|
This should be more robust, faster and easier to deal
with than the ugly proof-of-concept regexp-based ones.
|
|
With the 1.9.2preview1 release (and presumably 1.9.1 p243), the
Ruby core team has decided that bending over backwards to
support crippled operating/file systems was necessary and that
files must be closed before unlinking.
Regardless, this is more efficient than using Tempfile because:
1) no delegation is necessary, this is a real File object
2) no mkdir is necessary for locking, we can trust O_EXCL
to work properly without unnecessary FS activity
3) no finalizer is needed to unlink the file, we unlink
it as soon as possible after creation.
|
|
* maint:
unicorn 0.8.2
always set FD_CLOEXEC on sockets post-accept()
Minor cleanups to core
Re-add support for non-portable socket options
Retry listen() on EADDRINUSE 5 times ever 500ms
Unbind listeners as before stopping workers
Conflicts:
CHANGELOG
lib/unicorn.rb
lib/unicorn/configurator.rb
lib/unicorn/const.rb
|
|
FD_CLOEXEC is not guaranteed to be inherited by the accept()-ed
descriptors even if the listener socket has this set. This can
be a problem with applications that fork+exec long running
background processes.
Thanks to Paul Sponagl for helping me find this.
|
|
(cherry picked from commit ec70433f84664af0dff1336845ddd51f50a714a3)
|
|
This number of retries and delay taken directly from nginx
(cherry picked from commit d247b5d95a3ad2de65cc909db21fdfbc6194b4c9)
|
|
This allows another process to take our listeners
sooner rather than later.
(cherry picked from commit 8c2040127770e40e344a927ddc187bf801073e33)
|
|
|
|
There's a small memory reduction to be had when forking
oodles of processes and the Perl hacker in me still
gets confused into thinking those are arrays...
|
|
Array#+= creates a new array before assigning, Array#concat just
appends one array to another without an intermediate one.
|
|
This gives the app ability to deny clients with 417 instead of
blindly making the decision for the underlying application. Of
course, apps must be made aware of this.
|
|
This number of retries and delay taken directly from nginx
|
|
This allows another process to take our listeners
sooner rather than later.
|
|
Support for the "Trailer:" header and associated Trailer
lines should be reasonably well supported now
|
|
The complexity of making the object persistent isn't worth the
potential performance gain here.
|
|
Trying not to repeat ourselves. Unfortunately, Ruby 1.9 forces
us to actually care about encodings of arbitrary byte sequences.
|
|
This adds support for handling POST/PUT request bodies sent with
chunked transfer encodings ("Transfer-Encoding: chunked").
Attention has been paid to ensure that a client cannot OOM us by
sending an extremely large chunk.
This implementation is pure Ruby as the Ragel-based
implementation in rfuzz didn't offer a streaming interface. It
should be reasonably close to RFC-compliant but please test it
in an attempt to break it.
The more interesting part is the ability to stream data to the
hosted Rack application as it is being transferred to the
server. This can be done regardless if the input is chunked or
not, enabling the streaming of POST/PUT bodies can allow the
hosted Rack application to process input as it receives it. See
examples/echo.ru for an example echo server over HTTP.
Enabling streaming also allows Rack applications to support
upload progress monitoring previously supported by Mongrel
handlers.
Since Rack specifies that the input needs to be rewindable, this
input is written to a temporary file (a la tee(1)) as it is
streamed to the application the first time. Subsequent rewinded
reads will read from the temporary file instead of the socket.
Streaming input to the application is disabled by default since
applications may not necessarily read the entire input body
before returning. Since this is a completely new feature we've
never seen in any Ruby HTTP application server before, we're
taking the safe route by leaving it disabled by default.
Enabling this can only be done globally by changing the
Unicorn HttpRequest::DEFAULTS hash:
Unicorn::HttpRequest::DEFAULTS["unicorn.stream_input"] = true
Similarly, a Rack application can check if streaming input
is enabled by checking the value of the "unicorn.stream_input"
key in the environment hashed passed to it.
All of this code has only been lightly tested and test coverage
is lacking at the moment.
[1] - http://tools.ietf.org/html/rfc2616#section-3.6.1
|
|
Bah, it's so much busy work to deal with this as configuration
option. Maybe I should say we allow any logger the user wants,
as long as it's $stderr :P
|
|
Make us look even better in "Hello World" benchmarks!
Passing a third parameter to avoid the constant lookup
for the HttpRequest object doesn't seem to have a
measurable effect.
|
|
This should be faster/cheaper than using an instance variable
since it's accessed in a critical code path. Unicorn was never
designed to be reentrant or thread-safe at all, either.
|
|
This makes SIGHUP handling more consistent across different
configurations, and allows togging preload_app to take effect
when SIGHUP is issued.
|