Deployment
**********


Application server
==================

The author of "websockets" isn't aware of best practices for deploying
network services based on "asyncio", let alone application servers.

You can run a script similar to the server example, inside a
supervisor if you deem that useful.

You can also add a wrapper to daemonize the process. Third-party
libraries provide solutions for that.

If you can share knowledge on this topic, please file an issue.
Thanks!


Graceful shutdown
=================

You may want to close connections gracefully when shutting down the
server, perhaps after executing some cleanup logic. There are two ways
to achieve this with the object returned by "serve()":

* using it as a asynchronous context manager, or

* calling its "close()" method, then waiting for its "wait_closed()"
  method to complete.

Tasks that handle connections will be canceled. For example, if the
handler is awaiting "recv()", that call will raise "CancelledError".

On Unix systems, shutdown is usually triggered by sending a signal.

Here's a full example (Unix-only):

   #!/usr/bin/env python

   import asyncio
   import signal
   import websockets

   async def echo(websocket, path):
       async for message in websocket:
           await websocket.send(message)

   async def echo_server(stop):
       async with websockets.serve(echo, 'localhost', 8765):
           await stop

   loop = asyncio.get_event_loop()

   # The stop condition is set when receiving SIGTERM.
   stop = asyncio.Future()
   loop.add_signal_handler(signal.SIGTERM, stop.set_result, None)

   # Run the server until the stop condition is met.
   loop.run_until_complete(echo_server(stop))

"async" and "await" were introduced in Python 3.5. websockets supports
asynchronous context managers on Python ≥ 3.5.1. "async for" was
introduced in Python 3.6. Here's the equivalent for older Python
versions:

   #!/usr/bin/env python

   import asyncio
   import signal
   import websockets

   async def echo(websocket, path):
       while True:
           try:
               msg = await websocket.recv()
           except websockets.ConnectionClosed:
               break
           else:
               await websocket.send(msg)

   loop = asyncio.get_event_loop()

   # Create the server.
   start_server = websockets.serve(echo, 'localhost', 8765)
   server = loop.run_until_complete(start_server)

   # Run the server until receiving SIGTERM.
   stop = asyncio.Future()
   loop.add_signal_handler(signal.SIGTERM, stop.set_result, None)
   loop.run_until_complete(stop)

   # Shut down the server.
   server.close()
   loop.run_until_complete(server.wait_closed())

It's more difficult to achieve the same effect on Windows. Some third-
party projects try to help with this problem.

If your server doesn't run in the main thread, look at
"call_soon_threadsafe()".


Memory use
==========

In order to avoid excessive memory use caused by buffer bloat, it is
strongly recommended to tune buffer sizes.

Most importantly "max_size" should be lowered according to the
expected size of messages. It is also suggested to lower "max_queue",
"read_limit" and "write_limit" if memory use is a concern.


Port sharing
============

The WebSocket protocol is an extension of HTTP/1.1. It can be tempting
to serve both HTTP and WebSocket on the same port.

The author of "websockets" doesn't think that's a good idea, due to
the widely different operational characteristics of HTTP and
WebSocket.

"websockets" provide minimal support for responding to HTTP requests
with the "process_request()" hook. Typical use cases include health
checks. Here's an example:

   #!/usr/bin/env python

   # WS echo server with HTTP endpoint at /health/

   import asyncio
   import http
   import websockets

   def health_check(path, request_headers):
       if path == '/health/':
           return http.HTTPStatus.OK, [], b'OK\n'

   async def echo(websocket, path):
       async for message in websocket:
           await websocket.send(message)

   start_server = websockets.serve(
       echo, 'localhost', 8765, process_request=health_check)

   asyncio.get_event_loop().run_until_complete(start_server)
   asyncio.get_event_loop().run_forever()
