Date | Commit message (Collapse) |
|
Instead of trusting sysread/syswrite to throw EAGAIN if the pipe
is full (highly unlikely); just use non-blocking methods which
are indeed non-blocking and don't care for the #blocking= method
added to it.
|
|
Combining command-line and config file options in a reasonable
manner has and always will be a painful experience.
|
|
It makes test_exec more reliable and probably helps
other scripts people may run around this.
|
|
Instead of having global options for all listeners,
make all socket options per-listener. This allows
reverse-proxies to pick different listeners to get
different options on different sockets.
Given a cluster of machines (10.0.0.1, 10.0.0.2, 10.0.0.3)
running Unicorn with the following config:
------------------ 8< ----------------
listen "/tmp/local.sock", :backlog => 1
listen "*:8080" # use the backlog=1024 default
------------------ 8< ----------------
It is possible to configure a reverse proxy to try to use
"/tmp/local.sock" first and then fall back to using the
TCP listener on port 8080 in a failover configuration.
Thus the nginx upstream configuration on 10.0.0.1 to
compliment this would be:
------------------ 8< ----------------
upstream unicorn_cluster {
# reject connections ASAP if we are overloaded
server unix:/tmp/local.sock;
# fall back to other machines in the cluster via "backup"
# listeners which have a large backlog queue.
server 10.0.0.2:8080 backup;
server 10.0.0.3:8080 backup;
}
------------------ 8< ----------------
This removes the global "backlog" config option which
was inflexible with multiple machines in a cluster
and exposes the ability to change SO_SNDBUF/SO_RCVBUF
via setsockopt(2) for the first time.
|
|
This reworks error handling throughout the entire stack to be
more Ruby-ish. Exceptions are raised instead of forcing the
us to check return values.
If a client is sending us a bad request, we send a 400.
If unicorn or app breaks in an unexpected way, we'll
send a 500.
Both of these last-resort error responses are sent using
IO#write_nonblock to avoid tying Unicorn up longer than
necessary and all exceptions raised are ignored.
Sending a valid HTTP response back should reduce the chance of
us from being marked as down or broken by a load balancer.
Previously, some load balancers would mark us as down if we close
a socket without sending back a valid response; so make a best
effort to send one. If for some reason we cannot write a valid
response, we're still susceptible to being marked as down.
A successful HttpResponse.write() call will now close the socket
immediately (instead of doing it higher up the stack). This
ensures the errors will never get written to the socket on a
successful response.
|
|
Unicorn always uses lower-level sys{read,write} methods
when doing I/O so setting "client.sync=true" is just
a wasted operation.
|
|
They're easier for me to type and read and just barely faster
when doing comparisons on.
|
|
Instead of rotating logs immediately when SIGUSR1 is caught,
defer it until the current client is processing is complete.
This allows multi-line log messages generated by apps to not be
broken up if SIGUSR1 is received while the app is running.
If we're sleeping inside IO.select, we close a pipe in the
exceptfds set to cause EBADF to be raised.
This also adds a small reliability improvement to test_exec
so we wait until signals are ready before sending USR1
to rotate logs.
|
|
In case there are permissions problems that cause
log rotation to fail, we trap the error and defer
death until the current request finishes running.
|
|
bind_listen takes a hash as its second parameter now, allowing
the addition of :sndbuf and :rcvbuf options to specify the size
of the buffers in bytes. These correspond to the SO_SNDBUF and
SO_RCVBUF options via setsockopt(2) respectively.
This also adds support for per-listener backlogs to be used.
However, this is only an internal API change and the changes
have not yet been exposed to the user via Unicorn::Configurator,
yet.
Also add a bunch of SocketHelper tests
|
|
Since we always unlink existing sockets when binding, there's no
point in having code to unlink the sockets when we exit.
Additionally, the old code path was racy.
|
|
Only sleep if our signal queue is empty.
Remove redundant exception handling and go back to just
consuming the entire pipe since that's more efficient if we're
slammed with signals for whatever reason.
|
|
The master _may_ run with different user/group/umask than the
workers. Since the logs were always created by the master
process, the master should rotate them first to ensure correct
ownership and permissions.
This way if the workers fail log rotation and die, they'll
be automatically respawned with the new logs in place.
|
|
* Use waitpid2 to more reliably trap exit status
* Stop including Process namespace since it leads
to confusing conflicts.
|
|
This will only be enabled if we're daemonized and "real" WINCH
signals cannot be generated by resizing the terminal. This is
to avoid confusing developers who run in the foreground of a
terminal.
Additionally document procedures for reexecuting a running
binary.
|
|
Although I didn't like the idea initially, signal queueing
allows test_exec to run more reliably and the limited signal
queue size will prevent scary queued signal behavior.
Also, always wakeup the master immediately when CHLD is trapped
to reduce the performance impact of SIGHUP-based config
reloading. Combined with an extra check in test_exec, this
should make test_exec run much more reliably than before.
|
|
In nearly every app, if the current working directory
disappears, the app becomes broken, sometimes subtly. It can be
especially broken when preload_app is false (the default).
So just shut ourselves down to spare ourselves the
wasted CPU cycles on a dead app.
As a (hopefully) pleasant side effect, this allows
configurations with preload_app==false (the default) to do
application code reloads via SIGHUP (in addition to unicorn
config reloads).
|
|
This is useful for freeing certain resources you
do NOT want passed to child processes.
|
|
Unicorn will always continue to run in the directory it started
in, it does not chdir to "/". Since the default start_ctx[:cwd]
is symlink-aware, this should not be a problem for
Capistrano-deployed applications.
|
|
The $stderr/$stdout objects need to point to +File+ objects
and mot just +IO+ objects they default to for reopen_logs
to work.
|
|
Instead of blindly trying to bind to the default listener
(which is already the default as specified by Configurator).
|
|
|
|
As opposed to doing this in the shell, this allows the files to
be reopened reliably after rotation.
While we're at it, use $stderr/$stdout instead of STDERR/STDOUT
since they seem to be more favored.
|
|
This means processes will share less memory but things
should be compatible with all existing setups.
|
|
If we get woken up during an IO.select, just make a bet that we
spent some time doing something else and aggressively try to
accept new connections without trying to wait for I/O-readiness
notification.
|
|
I consider it a sensible default for long-running servers.
Additionally, there is no easy way to make USR1 rotate the
master process log without this.
|
|
Since I use it myself and also in the tests, we
might as well implement it correctly as a class method
so people can run it in their trap('USR2') hooks.
|
|
Using `/bin/sh -c pwd` here instead of Dir.pwd since
the pwd shell builtin is symlink-aware if ENV['PWD']
is correct (and it is when launched via Cap).
Also, correctly use @directory if it is set.
|
|
Relying on at_exit can still means a child might get it
if there's any race condition....
|
|
Some applications do not handle loading before forking
out-of-the-box very gracefully, this starts adding support
to build the Rack(-ish) application later in the process.
|
|
This allows Unicorn to be constantly started in symlink
paths such as the ones Capistrano creates
(e.g. "/u/apps/$app/current")
|
|
People can screw config files up, it's not my fault
if they do, but they do... Don't let the original
process get wedged if we can help it..
|
|
The Configurator includes error checking and opens the way for
better reloading/error-checking abilities.
This also renames many of the config settings with something
nginx-like to minimize the learning/setup curve since nginx is
the only recommended reverse-proxy for this.
s/pid_file/pid/
=> blech!, more confusing :<
s/listen_backlog/backlog/
=> maybe more confusing to some, or less...
s/nr_workers/worker_processes/
=> less confusing to non-AWKers for sure
s/hot_config_file/config_file/
=> the config file is now general purpose,
not just hot reloads
|
|
This will make setting some of this easier to deal
with in the executable.
|
|
This variable is not guaranteed to be updated outside
of an interactive POSIX-ish shell.
|
|
Since dying children can be a sign that something is wrong with
the app itself, continue to use the 1 wakeup/sec throttle and
don't wake the master immediately.
|
|
And avoid repeatedly sending kill -0 to each worker,
that nugget of stupid probably slipped in while I was
testing something...
|
|
This is to make things consistent with the other logging
when adding listeners
|
|
This can be overridden in {after,before}_fork hooks
of course; but makes things look a little nicer.
|
|
This allows changing certain variables without restarting the
master process or code reload. Currently, only the following
variables are supported: @timeout, @nr_workers, @hot_config_file.
Any other config changes will/should require re-executing the
running binary. This config file is run through eval(); so it
really users plenty of rope to hang themselves with. Of course,
it requires valid Ruby syntax:
------------------------- 8< ------------------------
@nr_workers = 8
@timeout = 15
@hot_config_file = "/var/tmp/new_hot_config_file"
------------------------- 8< ------------------------
Lowering the timeout will trigger all existing workers to be
gracefully stopped and restarted.
This file is loaded at startup, and overrides any config
settings that may already be loaded.
|
|
This controls the backlog argument to the listen(2) system call.
See your operating system documentation for listen(2) on the
specifics of this option.
The default is 1024, which is the same as Mongrel. 5 is the
default for Ruby TCPServer and UNIXServer; and in some case it
can be better where failover to a different machine/cluster
is properly configured.
|
|
* IO.pipe.map { } looks moronic, especially without
doing more inside it (like setting set_cloexec).
* No need to sleep when we have an unhandled master
loop exception (save for paranoia).
* client.class == TCPSocket is slightly more expensive
than TCPSocket === client
* nilify client to avoid GC from trying to close it
* Process.kill => kill
|
|
These files are unlinked immediately anyways, so
it's wasteful to give them a long name...
|
|
Don't rely on FD_CLOEXEC if we don't have to since it may not be
completely portable. Just explicitly close things (pipes,
tempfiles) we don't want to pass on to our children when
forking.
|
|
This makes it possible to bind per-process listener ports for
easier debugging. One of my biggest gripes about other prefork
webservers is that strace-ing the correct process for debugging
is difficult. This makes it possible for each worker to bind to
a unique port or UNIX socket independent of the other workers.
|
|
Workers have no business knowing these things...
|
|
If we're running in the foreground and don't care for process
manglement, then there's no need to start a pipe we won't need.
|
|
Like nginx, we'll replace the existing "pid_file" with
"pid_file.oldbin" when executing a new binary. We'll also
refuse to reexecute a new binary if the ".oldbin" pid file
already exists and points to a valid PID.
|
|
The timeout mechanism is implemented via shared tempfile handles
between the worker and master and checking the ctime of the
tempfile from the master. Instead of using sockets or pipes to
communicate between the workers and master, this allows the
master to avoid being overloaded with wakeups when the workers
are running at full crank (or this avoids having extra logic in
workers to throttle wakeup notifications to master).
The master still wakes up at a leisurely interval of once per
second to check, reap, or murder workers that are timed out.
[1] http://cr.yp.to/docs/selfpipe.html
|
|
This implements the self-pipe trick[1] to wakeup the master
process when signaled. We still wakeup every second to reap
workers and eventually check for timed out workers.
[1] http://cr.yp.to/docs/selfpipe.html
|