Date | Commit message (Collapse) |
|
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
|
|
We'll be using this flag with a pipe, too.
|
|
Along with worker process management. This is nginx-style
inplace upgrading (I don't know of another web server that does
this). Basically we can preserve our opened listen sockets
across entire executable upgrades.
Signals:
USR2 - Sending USR2 to the master unicorn process will cause
it to exec a new master and keep the original workers running.
This is useful to validate that the new code changes took place
are valid and don't immediately die. Once the changes are
validated (manually), you may send QUIT to the original
master process to have it gracefully exit.
HUP - Sending this to the master will make it immediately exec
a new binary and cause the old workers to gracefully exit.
Use this if you're certain the latest changes to Unicorn (and
your app) are ready and don't need validating.
Unlike nginx, re-execing a new binary will pick up any and all
configuration changes. However listener sockets cannot be
removed when exec-ing; only added (for now).
I apologize for making such a big change in one commit, but once
I got the ability to replace the entire codebase while preserving
connections, it was too tempting to continue working.
So I wrote a large chunk of this while hitting
the unicorn-hello-world app with the following loop:
while curl -vSsfN http://0:8080; do date +%N; done
_Zero_ requests lost across multiple restarts.
|
|
Keeping I/O out of unicorn.rb
|
|
This allows us to avoid the overhead of allocating a new buffer
each and every time we call sysread (even when just parsing
headers for GET requests).
|
|
Unicorn is only designed for fast internal networks (and
loopback); so avoid wasting time with userspace I/O buffering.
This should not significantly affect userspace threading on 1.8
in case your application itself is running threads for some
(masochistic) reason as long as the clients you're serving
directly with Unicorn are fast.
|
|
We're not currently using them; and I don't see the need to
ever use either...
|
|
While we'll support anything that exposes a Rack-like interface
(a very good one IMHO), we shouldn't have a hard dependency on
Rack to simplify testing.
While we're at it, I'm not using Daemons anymore, either,
since that does too many things behind our back as far as
daemonization goes.
As a result of not depending on Rubygems, either, I've sped
up my "make -j" test ~1.5 seconds
|
|
Keep this somewhat consistent with the HttpParser API
which also exposes #reset instead of #reset!
|
|
Just stuff what little logic we had for it into HttpResponse
since Rack takes care of the rest for us.
Put the HTTP_STATUS_HEADERS hash in HttpResponse since we're the
only user of it. Also, change HttpResponse.send to
HttpResponse.write to avoid overriding the default method.
|
|
Use select(2) to multiplex non-blocking accept(2) calls between
them. Additionally, aggressively make a bet after accepting
clients where we'll try to do a non-blocking accept(2) against
the full set of descriptors. This is based on the assumption
that if we just accepted connections, we're probably reasonably
busy.
This should lead to lower latency under high load; but some
wasted cycles when requests come in intermitently. By this same
logic, we don't really care for the thundering herd problem,
either; since it is only noticeable with many (hundreds) of
processes when most of them are idle.
|
|
Additionally, provide Socket#unicorn_addr which makes it
easy to determine whether a given Socket matches one in
the config.
|
|
We'll be supporting UNIX domain sockets soon... Get rid of
tcphack since it was overriding a default method and just
manually call Socket.new, bind, listen ourselves. Additionaly,
use SO_REUSEADDR when binding since it is convenient for
restarts.
|
|
This will help prevent TMPDIR from becoming bloated when
handling thousands of large uploads a day. This is a problem in
many UNIX filesystems (including ext3): names of entries never
expire even after files are gone and the only way to clear it is
to get rid of the directory itself.
|
|
It's pointless...
|
|
The previous API was very flexible, but I don't think many
people really cared for it... We now repeatedly use the
same HeaderOut in each process since I completely don't
care for multithreading.
|
|
It's really pointless to allow stdio or something
similar to do any sort of buffering on a TCP socket
on a Linux box where syscalls are cheap and we have
TCP_CORK.
|
|
All tests for threading and semaphores have been removed. One
test was changed because it depended on a shared variable.
Tests will be replaced with tests to do process management
instead.
|
|
Avoid conflicting with existing Mongrel libraries since
we'll be incompatible and break things w/o disrupting
Mongrel installations.
|