summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2012-01-02 18:10:18 -0500
committerChris McDonough <chrism@plope.com>2012-01-02 18:10:18 -0500
commit31af60d18a625b1aee76205beb8e0bca3ce73143 (patch)
tree0aa297a6b202c8e064b14d83aac7afacad0d085d
parent359257a9da47b398f68b84b12e07283ead9414b4 (diff)
downloadwaitress-31af60d18a625b1aee76205beb8e0bca3ce73143.tar.gz
add design document
-rw-r--r--docs/design.rst54
-rw-r--r--docs/glossary.rst5
-rw-r--r--docs/index.rst1
3 files changed, 60 insertions, 0 deletions
diff --git a/docs/design.rst b/docs/design.rst
new file mode 100644
index 0000000..69731a7
--- /dev/null
+++ b/docs/design.rst
@@ -0,0 +1,54 @@
+Design
+------
+
+Waitress uses a combination of asynchronous and synchronous code to do its
+job. It handles I/O to and from clients using the :term:`asyncore` library.
+
+The :term:`asyncore` module in the Python standard library:
+
+- Uses the ``select.select`` function to wait for connections from clients
+ and determine if a connected client is ready to receive output.
+
+- Creates a channel whenever a new connection is made to the server.
+
+- Executes methods of a channel whenever it believes data can be read from or
+ written to the channel.
+
+A "channel" is created for each connection from a client to the server. The
+channel handles all requests over the same connection from that client. A
+channel will handle some number of requests during its lifetime: zero to how
+ever many HTTP requests are sent to the server by the client over a single
+connection. For example, an HTTP/1.1 client may issue a theoretically
+infinite number of requests over the same connection; each of these will be
+handled by the same channel. An HTTP/1.0 client without a "Connection:
+keep-alive" header will request usually only one over a single TCP
+connection, however, and when the request has completed, the client
+disconnects and reconnects (which will create another channel). When the
+connection related to a channel is closed, the channel is destroyed and
+garbage collected.
+
+When a channel determines the client has sent at least one full valid HTTP
+request, it schedules a "task" with a "thread dispatcher". The thread
+dispatcher maintains a fixed pool of worker threads available to do client
+work (by default, 4 threads). If a worker thread is available when a task is
+scheduled, the worker thread runs the task. The task has access to the
+channel, and can write back to the channel's output buffer. When all worker
+threads are in use, scheduled tasks will wait in a queue for a worker thread
+to become available.
+
+I/O is always done asynchronously (by asyncore) in the main thread. Worker
+threads never do any I/O. This means that 1) a large number of clients can
+be connected to the server at once and 2) worker threads will never be hung
+up trying to send data to a slow client.
+
+No attempt is made to kill a "hung thread". It's assumed that when a task
+(application logic) starts that it will eventually complete. If for some
+reason WSGI application logic never completes and spins forever, the worker
+thread related to that WSGI application will be consumed "forever", and if
+enough worker threads are consumed like this, the server will stop responding
+entirely.
+
+Periodic maintenance is done by the main thread (the thread handling I/O).
+If a channel hasn't sent or received any data in a while, the channel's
+connection is closed, and the channel is destroyed.
+
diff --git a/docs/glossary.rst b/docs/glossary.rst
index ac17a19..ad0876b 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -10,3 +10,8 @@ Glossary
A system for configuration of WSGI web components in declarative
``.ini`` format. See http://pythonpaste.org/deploy/.
+ asyncore
+ A standard library module for asynchronous communications. See
+ http://docs.python.org/library/asyncore.html .
+
+
diff --git a/docs/index.rst b/docs/index.rst
index e421491..6882731 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -180,6 +180,7 @@ Extended Documentation
.. toctree::
:maxdepth: 1
+ design.rst
differences.rst
api.rst
arguments.rst