Skip to content

Commit

Permalink
Merge pull request #226 from twillis/master
Browse files Browse the repository at this point in the history
update asgi example to asgi 3.0 protocol
  • Loading branch information
stevepiercy committed Jul 2, 2020
2 parents f412f0a + 3128889 commit cc039c8
Showing 1 changed file with 42 additions and 26 deletions.
68 changes: 42 additions & 26 deletions docs/deployment/asgi.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
ASGI (Asynchronous Server Gateway Interface)
++++++++++++++++++++++++++++++++++++++++++++

This chapter contains information about using ASGI with Pyramid. Read about the `ASGI specification <https://asgi.readthedocs.io/en/latest/index.html>`_.
This chapter contains information about using ASGI with Pyramid.
Read about the `ASGI specification <https://asgi.readthedocs.io/en/latest/index.html>`_.

The example app below uses the WSGI to ASGI wrapper from the `asgiref library <https://pypi.org/project/asgiref/>`_ to transform normal WSGI requests into ASGI responses. This allows the application to be run with an ASGI server, such as `uvicorn <https://www.uvicorn.org/>`_ or `daphne <https://github.com/django/daphne/>`_.
The example app below uses the WSGI to ASGI wrapper from the `asgiref library <https://pypi.org/project/asgiref/>`_ to transform normal WSGI requests into ASGI responses.
This allows the application to be run with an ASGI server, such as `uvicorn <https://www.uvicorn.org/>`_ or `daphne <https://github.com/django/daphne/>`_.


WSGI -> ASGI application
Expand All @@ -14,7 +16,7 @@ This example uses the wrapper provided by ``asgiref`` to convert a WSGI applicat
Please note that not all extended features of WSGI may be supported, such as file handles for incoming POST bodies.

.. code-block:: python
# app.py
from asgiref.wsgi import WsgiToAsgi
Expand All @@ -37,10 +39,11 @@ Please note that not all extended features of WSGI may be supported, such as fil
Extended WSGI -> ASGI WebSocket application
-------------------------------------------

This example extends the ``asgiref`` wrapper to enable routing ASGI consumers alongside the converted WSGI application. This is just one potential solution for routing ASGI consumers.
This example extends the ``asgiref`` wrapper to enable routing ASGI consumers alongside the converted WSGI application.
This is just one potential solution for routing ASGI consumers.

.. code-block:: python
# app.py
from asgiref.wsgi import WsgiToAsgi
Expand All @@ -57,16 +60,29 @@ This example extends the ``asgiref`` wrapper to enable routing ASGI consumers al
super().__init__(*args, **kwargs)
self.protocol_router = {"http": {}, "websocket": {}}
def __call__(self, scope, **kwargs):
async def __call__(self, scope, *args, **kwargs):
protocol = scope["type"]
path = scope["path"]
try:
consumer = self.protocol_router[protocol][path]
except KeyError:
consumer = None
if consumer is not None:
return consumer(scope)
return super().__call__(scope, **kwargs)
await consumer(scope, *args, **kwargs)
await super().__call__(scope, *args, **kwargs)
if consumer is not None:
await consumer(scope, *args, **kwargs)
try:
await super().__call__(scope, *args, **kwargs)
except ValueError as e:
# The developer may wish to improve handling of this exception.
# See https://github.com/Pylons/pyramid_cookbook/issues/225 and
# https://asgi.readthedocs.io/en/latest/specs/www.html#websocket
pass
except Exception as e:
raise e
def route(self, rule, *args, **kwargs):
try:
Expand Down Expand Up @@ -127,39 +143,38 @@ This example extends the ``asgiref`` wrapper to enable routing ASGI consumers al
# Define ASGI consumers
@app.route("/ws", protocol="websocket")
def hello_websocket(scope):
async def asgi_instance(receive, send):
while True:
message = await receive()
if message["type"] == "websocket.connect":
await send({"type": "websocket.accept"})
if message["type"] == "websocket.receive":
text = message.get("text")
if text:
await send({"type": "websocket.send", "text": text})
else:
await send({"type": "websocket.send", "bytes": message.get("bytes")})
return asgi_instance
async def hello_websocket(scope, receive, send):
while True:
message = await receive()
if message["type"] == "websocket.connect":
await send({"type": "websocket.accept"})
elif message["type"] == "websocket.receive":
text = message.get("text")
if text:
await send({"type": "websocket.send", "text": text})
else:
await send({"type": "websocket.send", "bytes": message.get("bytes")})
elif message["type"] == "websocket.disconnect":
break
Running & Deploying
-------------------

The application can be run using an ASGI server:
The application can be run using an ASGI server:

.. code-block:: bash
$ uvicorn app:app
or
or

.. code-block:: bash
$ daphne app:app
There are several potential deployment options, one example would be to use `nginx <https://nginx.org/>`_ and `supervisor <http://supervisord.org/>`_. Below are example configuration files that run the application using ``uvicorn``, however ``daphne`` may be used as well.
There are several potential deployment options, one example would be to use `nginx <https://nginx.org/>`_ and `supervisor <http://supervisord.org/>`_.
Below are example configuration files that run the application using ``uvicorn``, however ``daphne`` may be used as well.


Example nginx configuration
Expand Down Expand Up @@ -207,4 +222,5 @@ Example Supervisor configuration
autostart=true
autorestart=true
redirect_stderr=True
[supervisord]

0 comments on commit cc039c8

Please sign in to comment.