Date | Commit message (Collapse) |
|
When a client attempts to reuse a session, we must have a
session_id_context set or else handshakes fail. This problem
manifests only with clients which attempt to reuse stored
sessions. This is irrespective of any session caching
configured (even if explicitly disabled) in the server.
The SSL_CTX_set_session_id_context(3SSL) manpage states:
If the session id context is not set on an SSL/TLS server and
client certificates are used, stored sessions will not be reused
but a fatal error will be flagged and the handshake will fail.
|
|
env['HTTPS'] is not documented in rack SPEC, but appears to be
used by Rack::Request since 2010[*]. Also, set rack.url_scheme
as documented by rack SPEC.
[*] - commit 4defbe5d7c07b3ba721ff34a8ff59fde480a4a9f
("Improves performance by lazy loading the session.")
|
|
By explicitly calling OpenSSL::SSL::SSLContext#setup before
accepting connections. We cannot rely on "setup" being called
implicitly because any callbacks configured or objects
configured by the client may not be thread-safe.
We also avoid calling "setup" in the master process (if yahns is
configured to use worker processeses) in case the setup code
starts any TCP connections (e.g. to memcached for session
caching).
|
|
Using the 'update-copyright' script from gnulib[1]:
git ls-files | UPDATE_COPYRIGHT_HOLDER='all contributors' \
UPDATE_COPYRIGHT_USE_INTERVALS=2 \
xargs /path/to/gnulib/build-aux/update-copyright
We're also switching to 'GPL-3.0+' as recommended by SPDX
to be consistent with our gemspec and other metadata
(as opposed to the longer but equivalent "GPLv3 or later").
[1] git://git.savannah.gnu.org/gnulib.git
|
|
There are likely yet-to-be-discovered bugs in here.
Also, keeping explicit #freeze calls for 2.2 users, since most
users have not migrated to 2.3, yet.
|
|
Remove unnecessary anonymous procs and conditionals to save some
bytecode memory Also, no valid PID can be zero, as kill(2)
treats zero specially.
|
|
Reduce unnecessary arguments to "exit" and "exit!". Additionally,
rely on a "putnil" instruction rather than a "putstring" argument
with an unnecessary string operand for an uncommon code path.
|
|
Future updates may use the update-copyright script in gnulib:
git ls-files | UPDATE_COPYRIGHT_HOLDER='all contributors' \
UPDATE_COPYRIGHT_USE_INTERVALS=2 \
xargs /path/to/gnulib/build-aux/update-copyright
|
|
systemd socket emulation shares FDs across execve, just like
the built-in SIGUSR2 upgrade process in unicorn. Thus it is
easy to support inheriting sockets from systemd.
|
|
TCP socket options are now set when inheriting existing sockets from
a parent process. I'm fairly certain all the TCP setsockopt knobs
we use are idempotent and harmless to change.
If anything, the only directive I'd be uncomfortable changing is
shortening the listen(2) (aka :backlog) size, but we've always
changed that anyways since it also applies to UNIX sockets.
Note: removing a configuration knob in a yahns config file can not
reset the value to the OS-provided default setting. Inherited
sockets must use a new setting to override existing ones.
(or the socket needs to be closed and re-created in the process
launcher before yahns inherits it).
Based on unicorn commit 1db9a8243d42cc86d5ca4901bceb305061d0d212
Noticed-by: Christos Trochalakis <yatiohi@ideopolis.gr>
<20150626114129.GA25883@luke.ws.skroutz.gr>
|
|
The monotonic clock is immune to time adjustments so it is not
thrown off by misconfigured clocks. Process.clock_gettime also
generates less garbage on 64-bit systems due to the use of Flonum.
|
|
The current CA model and code quality of OpenSSL have long put me off
from supporting TLS; however but efforts such as "Let's Encrypt"
and the fallout from Heartbleed give me hope for the future.
This implements, as much as possible, a "hands-off" approach to TLS
support via OpenSSL. This implementation allows us to shift
responsibility away from us to users and upstreams (the Ruby 'openssl'
extension maintainers, software packagers, and OpenSSL project itself).
This is also perhaps the easiest way for now for us, while being most
powerful for users. It requires users to configure their own OpenSSL
context object which we'll use as-is.
This context object is used as the :ssl_ctx parameter to the "listen"
directive in the yahns configuration file:
require 'openssl' # we will not do this for the user, even
ctx = OpenSSL::SSL::SSLContext.new
# user must configure ctx here...
listen 443, ssl_ctx: ctx
This way, in case we support GnuTLS or other TLS libraries, there'll
be less confusion as to what a user is actually using.
Note: this feature requires Ruby 2.1 and later for non-kgio
{read,write}_nonblock(.. exception: false) support.
|
|
This barely reduces garbage objects at startup, but less
garbage is usually better.
|
|
Replacing a Regexp argument to a rarely-called String#split with a
literal String can save some memory. Each removed Regexp memsize is
469 bytes on Ruby 2.1, and Ruby does not currently deduplicate
literal Regexps.
On Ruby 2.1, the "objspace" extension shows:
ObjectSpace.memsize_of(/,/) => 469
Is slightly smaller at 453 bytes on 2.2.0dev (r48474), and
these numbers do not include the 40-byte object overhead.
Nevertheless, this is a waste for non-performance-critical code
during the startup phase. Identical literal strings are
automatically deduplicated by Ruby 2.1, and has no additional
overhead because Rack (and likely some real apps) also includes
several instances of the literal "," byte.
We'll drop the unnecessary "encoding: binary" magic comment
in yahns/server.rb as well, as that file includes no literal
binary strings.
The downside of using a literal string argument in these cases is
a 40-byte object gets allocated on every call, but the affected
pieces of code are only called once in a process lifetime.
|
|
This speeds up searching during startup and prevents accidentally
misloading different, potentially incompatible versions of yahns
code.
|
|
This prevents potential errors and compatibility problems with
buggy libraries which do not respond well to signal delivery.
Based on unicorn commit 6f6e4115b4bb03e5e7c55def91527799190566f2
|
|
When daemonizing, it is possible for the grandparent to be
terminated by another process before the master can notify
it. Do not abort the master in this case.
unicorn commit 27ae210dde9228cfa96ea6b0f3a7e4047d3f70a4
|
|
Our QueueQuitter may race with epoll_wait and GC, potentially
triggering memory corruption if a level-trigger object was
placed into the ready list and no longer referenced.
We'll work around this problem by making the QueueQuitter object
a thread-local (on thread failure) to prevent concurency issues
where the epoll pointer no longer points to a Ruby object.
|
|
The first argument of the old __expire_for method was completely
unused in all but one invocation of it, so it is not worth it. This
also simplifies the code a bit too.
|
|
apps/responses may trickle infinitely, so our QueueQuitter may
not properly kill epoll worker threads, unfortunately. So we'll
start the timer and stop waiting (risking segfaults/ugliness) by
closing epoll descriptors
|
|
We must know we're daemonized after a SIGUSR2 upgrade, even if we
don't use the pipe to signal to the controlling terminal we've
started up.
|
|
This may happen if we get by a forceful exit, so we'll risk
triggering some bugs elsewhere, but forceful exits are never
pretty...
|
|
It may be disconcerting to not know how long it takes a server
to gracefully exit, so provide that feedback. While we're at
it, avoid dropping acceptors if we want a forceful exit.
|
|
We must not reap processes we did not spawn if we're not using a
master/worker configuration. This may break applications which
depend on waitpid themselves. However we still trap SIGCHLD
currently. In the future, we could switch our notification
model mode to be compatible with apps which depend on SIGCHLD or
might indiscriminately on children (which might prevent us from
knowing about SIGCHLD).
|
|
Array#join implies string conversion and unicorn has been
doing that for ages.
|
|
It's conceivable a sub-optimally configured instance can have too
many Unix sockets connected to us. This also implements expiry for
systems without sufficient "struct tcp_info" support.
|
|
It was totally unnecessary and just made things hard-to-follow.
|
|
Users of other web servers may be surprised there is no recommended
way to have a new instance of yahns inherit from another web server.
|
|
This allows modifying the command-line (as an array) passed to
Kernel#exec, as well as running anything necessary.
|
|
Otherwise, the server may stay running forever if a client chooses
to stay forever (and there is no FD pressure).
|
|
This saves about 200 bytes of unswappable kernel memory,
so it might matter for systems with many connections
when hijacking.
|
|
Oops, this was only noticed when inheriting a descriptor
we want to close.
|
|
This is probably not needed and just adds contention, but it makes
experimenting easier.
While we're at it, validate minimum values of for sndbuf/rcvbuf
along with this new threads value, too.
|
|
Unfortunately, my eyes are more-or-less trained to ignore
documentation when I edit code.
|
|
This was documented (incorrectly) and not implemented for either
the master/worker or single process cases. Implement and test
all (with mocks, so not fully-tested).
|
|
We do not want users to use the default queue unless an app
context requires it. We also do not want to spin up the default
queue unless we are sure we have app contexts using it (and
not private/anonymous queues).
|
|
This should make things a little easier-to-follow and possibly
improve method cache hit rates for servers with multiple acceptors.
|
|
We'll hit SIGCHLD if our reexec process fails on us, so the
non-MP server must handle it, too. We discovered this bug
while porting the PID file renaming changes from unicorn.
|
|
pipes and eventfd are always writable after creation, thus
there's no need to trigger it and watch for readability.
This saves us some code in the Linux case (and we currently
only support GNU/Linux).
|
|
These can be used to disconnect/reconnect to databases
and other external connections. These are named to match
the documentation of pthread_atfork(3)
|
|
Having a backtrace would be nice, actually.
|
|
|
|
Calling close on the socket while accept4 is running on a different
thread can be problematic on Rubinius and some versions of MRI.
So we will use a thread-local variable, continuously issue new
connections to our own socket and rely on the round-robin behavior
of accept4 to eventually get our acceptor thread to wakeup.
We must continuously issue new connections because some connections
may be going to a new processes (from SIGUSR2). We cannot use
shutdown for the same reason.
|
|
This could still be useful since new listeners may be newly
shut down and the socket is still in the process of being released
in the kernel.
|
|
Leaving acceptor threads running cause client-visible errors because the
last accepted socket may enter (or attempt to enter) the queue before
the queue is shutdown. Leaving a worker queue thread running can be
problematic, too, since it can trigger bugs in the Ruby implementation
(which we'll track down and fix).
|
|
It will be converted to a string anyways, so do not bother.
|
|
This seems problematic on rbx (and their bugtracker requiring access
to a non-Free SaaS is an inconvenience to me). Also, improve
the robustness of our acceptors in case by rescuing Thread#join
as well.
|
|
|
|
There is no way we can rely on any potential vfork optimization
given our use of redirects (vfork only pauses calling thread).
This partially reverts commit d973de0d6dfdf799e111d9f9a71170b61a0ac100
|
|
Acceptors require closing the descriptor, first, and then doing a
(nasty) cross-thread exception to kick the thread out of the blocking
accept via Thread#run (pthread_kill SIGVTALRM). We cannot do what we're
doing with epoll with acceptors because the accept socket is shared
across processes. We will also NEVER be using non-blocking accept, as
it's more important we fairly distribute connections between tasks when
we're not shutting the server down.
The queue worker threads are much easier to kill off :) We can simply
inject a new QueueQuitter object as a Level-Triggering epoll watch,
activate it, and let it wreak havok on all the worker threads from a
single event activation.
rb_thread_fd_close is convenient, but expensive with many threads, so be
prepared for more systems without it. This is for Rubinius compatibility.
Yes, we are actually using Level-Triggered epoll here (despite the
non-shutdown pieces of our code being based around EPOLLONESHOT).
|