Date | Commit message (Collapse) |
|
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.
|
|
There is a potential race condition in closing the tempfile
immediately after SIGKILL-ing the child. So instead just
close it when we reap the dead child.
Some some versions of Ruby may also not like having the
WORKERS hash being changed while it is iterating through
each_pair, so dup the hash to be on the safe side (should
be cheap, since it's not a deep copy) since kill_worker()
can modify the WORKERS hash.
This is somewhat of a shotgun fix as I can't reproduce the
problem consistently, but oh well.
|
|
This should prevent Rack from being required too early
on so "-I" being passed through the unicorn command-line
can modify $LOAD_PATH for Rack
|
|
No point in refreshing the list of gems unless the app
can actually be reloaded.
|
|
On application reloads, Gems installed by the Ruby instance may
be different than when Unicorn started. So when preload_app is
false, HUP-ing Unicorn will always refresh the list of Gems
before loading the application code.
|
|
There may be other logs opened if preload_app is true
besides stderr/stdout paths. So err on the safe side
and reopen everything.
|
|
This used to happen on machines that were coming out of
suspend/hibernation.
|
|
These potentially leaves an open file handle around until the
next request hits the process, but this makes the common case
faster.
|
|
|
|
First, reduce no-op fchmod syscalls under heavy traffic.
gettimeofday(2) is a cheaper syscall than fchmod(2). Since
ctime resolution is only in seconds on most filesystems (and
Ruby can only get to seconds AFAIK), we can avoid fchmod(2)
happening within the same second. This allows us to cheat on
synthetic benchmarks where performance is measured in
requests-per-second and not seconds-per-request :)
Secondly, cleanup the acceptor loop and avoid nested
begins/loops as much as possible. If we got ECONNABORTED, then
there's no way the client variable would've been set correctly,
either. If there was something there, then it is at the mercy
of the garbage collector because a method can't both return a
value and raise an exception.
|
|
Use SIGQUIT if you're going to be nice and do graceful
shutdowns. Sometimes people run real applications on this
server and SIGINT/SIGTERM get lost/trapped when Object is
rescued and that is not good. Also make sure we break out of
the loop properly when the master is dead.
Testcases added for both SIGINT and dead master handling.
|
|
If our response succeeds, we've already closed the socket.
Otherwise, we would've raised an exception at some point hit one
of the rescue clauses.
|
|
This makes it easier to use "killall -$SIGNAL unicorn"
without having to lookup the correct PID.
|
|
Timeouts of less than 2 seconds are unsafe due to the lack of
subsecond resolution in most POSIX filesystems. This is the
trade-off for using a low-complexity solution for timeouts.
Since this type of timeout is a last resort; 2 seconds is not
entirely unreasonable IMNSHO. Additionally, timing out too
aggressively can put us in a fork loop and slow down the system.
Of course, the default is 60 seconds and most people do not
bother to change it.
|
|
Since we've switched to readpartial, we'll already be protected
from any unpleasant errors that might get thrown at us. There's
no easy way to prevent MRI from calling a select() internally to
check for readiness, so speculative+blocking read() calls are
out already.
Additionally, most requests come in the form of GETs which are
fully-buffered in the kernel before we even accept() the socket;
so a single readpartial call will be enough to fully consume it.
|
|
Only do speculative accept on the previous ready set of
listeners. This makes it less CPU-intensive to have per-process
debug listeners configured.
Unfortunately, this makes non-primary listeners unable to accept
connections if the server is under extremely heavy load and
speculative accept() on the previous listener is always
succeeding and hogging the process. Fortunately, this is an
uncommon case.
|
|
No need to use ensure since process_client will handle errors
regardless. And if not, there's a bug on our side that needs to
fixed.
|
|
We were closing a no-longer-existent I/O object to break out of
IO.select. This was broken in 0.6.0 but did not affect the
worker when it was busy.
|
|
We do this in both the worker and master processes, so avoid
repeating ourselves.
|
|
This allows dynamic tuning of the worker_processes count without
having to restart existing ones. This also allows
worker_processes to be set to a low initial amount in the config
file for low-traffic deployments/upgrades and then scaled up as
the old processes are killed off.
Remove the proposed reexec_worker_processes from TODO since this
is far more flexible and powerful.
This will allow not-yet-existent third-party monitoring tools to
dynamically change and scale worker processes according to site
load without increasing the complexity of Unicorn itself.
|
|
Seems like a good idea to be able to relocate log
files on a config reload.
|
|
Saying to the world that I may have OCD...
|
|
As long as our speculative accept()s are succeeding, then avoid
checking for master process death and keep processing requests.
This allows us to save some syscalls under extremely heavy
traffic spikes.
|
|
Oops, this was broken in another yak-shaving commit:
9206bb5e54a0837e394e8b1c1a96e27ebaf44e77
|
|
Avoid scaring the thread-safety-first crowd (as much :)
|
|
Since it has to work inside signal handlers, there's
no point in making it a per-object instance variable
given the price of an instance variable in MRI...
|
|
Instance variables are expensive and we'd be encouraging
something like a thread-safe mentality for using ivars
when dealing with things that are global to the entire
process.
|
|
Since file descriptors are only private to a process,
do not treat them as Object-specific.
|
|
|
|
It's pointless to support multiple instances of it since
this is per-process. However, the constant itself is now
modifiable if anybody needs to tweak things for reexecution
using a before_exec hook.
|
|
We no longer have anything outside of SocketHelper module in
that file, so just give it a more obvious name.
|
|
Oops, that was not just speculative accept(), but
spammy accept()...
|
|
Ensure we always fchmod our tempfile in case of client error to
avoid getting nuked in the next request cycle. Also, kill off
some unnecessary variables since this method has too many
variables anyways and we can overload the "nr" counter to do
what "accepted" and "reopen_logs" did..
|
|
So don't bother checking them again. Configurator already
ensures that they're Proc objects for us, and we've been
forgetting to check @before_fork since the beginning of
time anyways... Consistency + less code = good
|
|
We don't (and won't ever) do log rotation within the process.
That's the job of logrotate and tools like that. We just
reopen logs like other reasonable daemons out there.
|
|
Otherwise we get generally worthless backtraces and we don't
want to clobber those for other signals, either.
|
|
By reraising SignalException in workers. Since we just rely on
default signal handlers for the majority of signals now, ensure
those signals actually exit the process.
|
|
Instead of just worker.nr. This is a configuration file/API
change and will break existing configurations.
This allows worker.tempfile to be exposed to the hooks
so ownership changes can still happen on it.
On the other hand, I don't know of many people actually
using this feature (or Unicorn).
|
|
I'm golfing, really, but maybe we can be 0.00001% faster
if we avoid naming some variables...
|
|
Since signals and signal handlers are process-wide, just make
SIG_QUEUE a global constant since there's absolutely no reason
it should be otherwise...
Restore default signal handlers when building app in case our
app does anything strange or gets hung, it's nice to know
SIG{INT,TERM} can be used to kill it while it's loading.
Additionally, there's little point in clearing arrays before
nilling them: just trust the GC to do its job properly.
|
|
If someone changes ENV or umask in the master process (via
before_fork or when loading the config), assume it was
intentional and just preserve it across reexec.
|
|
We never write to the file anyways, and fchmod is never buffered
|
|
MRI 1.8 always sets O_NONBLOCK on sockets to implement green
threads correctly in the face of slow network I/O. Since we
already know what the I/O flags for a client socket should be,
we just set it to that instead.
Applications running on Unicorn continue to be green thread-safe
when used fast local traffic. Of course, Unicorn itself will
never use threads.
|
|
Unicorn is strictly for fast LAN and localhost clients. Unicorn
is not for slow, high-latency or trickling clients and cannot do
keepalive or pipelining.
None of the removed options actually make sense
in the environment Unicorn was designed for.
* DEFER_ACCEPT/ACCEPT_FILTER - these are useful for mitigating
connect() floods or trickling clients. We shouldn't have to
deal with those on a trusted LAN.
* TCP_CORK/TCP_NODELAY - we only send output in the response and
then immediately close the socket. Assuming the typical
response containing a small header and large strings in the
body: the Nagle algorithm would've corked the headers
regardless and any pending output would be immediately flushed
when the socket is closed immediately after sending.
These options would still be useful from the client-side on
the LAN, or if Unicorn supported keepalive.
Of course, I highly recommend enabling all of these options
you can possibly enable on nginx or another fully-buffering
reverse proxy when dealing with slow clients.
|
|
Apparently I was smoking crack and thought they weren't
changeable. Additionally, SO_REUSEADDR is set by TCPServer.new,
so there's no need to set it ourselves; so avoid putting
extra items in the purgatory.
This allows SIGHUP to change listen options.
|
|
Sockets may be unintentionally unlinked on the filesystem.
When reloading our config, ensure that the socket exists
on the filesystem. If not, close the listener (since it's
unusable by outside apps) and reopen it.
|
|
Rather than blindly appending to our listener set
with every "listen" directive read in the config
file, reset our internal array.
Listeners specified on the command-line are always
preserved between config reloads.
|