-
-
Notifications
You must be signed in to change notification settings - Fork 816
Add error handling and enable graceful shutdown #2131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,21 @@ | ||
| import logging | ||
| import traceback | ||
|
|
||
| from channels.consumer import AsyncConsumer | ||
|
|
||
| from ..db import aclose_old_connections | ||
| from ..exceptions import StopConsumer | ||
|
|
||
| logger = logging.getLogger("channels.consumer") | ||
| if not logger.hasHandlers(): | ||
| handler = logging.StreamHandler() | ||
| formatter = logging.Formatter( | ||
| "%(asctime)s - %(name)s - %(levelname)s - %(message)s" | ||
| ) | ||
| handler.setFormatter(formatter) | ||
| logger.addHandler(handler) | ||
| logger.setLevel(logging.DEBUG) | ||
|
|
||
|
|
||
| class AsyncHttpConsumer(AsyncConsumer): | ||
| """ | ||
|
|
@@ -17,10 +30,6 @@ async def send_headers(self, *, status=200, headers=None): | |
| """ | ||
| Sets the HTTP response status and headers. Headers may be provided as | ||
| a list of tuples or as a dictionary. | ||
|
|
||
| Note that the ASGI spec requires that the protocol server only starts | ||
| sending the response to the client after ``self.send_body`` has been | ||
| called the first time. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you undo all of these unrelated changes to comments please.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am so sorry about these |
||
| """ | ||
| if headers is None: | ||
| headers = [] | ||
|
|
@@ -34,10 +43,6 @@ async def send_headers(self, *, status=200, headers=None): | |
| async def send_body(self, body, *, more_body=False): | ||
| """ | ||
| Sends a response body to the client. The method expects a bytestring. | ||
|
|
||
| Set ``more_body=True`` if you want to send more body content later. | ||
| The default behavior closes the response, and further messages on | ||
| the channel will be ignored. | ||
| """ | ||
| assert isinstance(body, bytes), "Body is not bytes" | ||
| await self.send( | ||
|
|
@@ -46,18 +51,14 @@ async def send_body(self, body, *, more_body=False): | |
|
|
||
| async def send_response(self, status, body, **kwargs): | ||
| """ | ||
| Sends a response to the client. This is a thin wrapper over | ||
| ``self.send_headers`` and ``self.send_body``, and everything said | ||
| above applies here as well. This method may only be called once. | ||
| Sends a response to the client. | ||
| """ | ||
| await self.send_headers(status=status, **kwargs) | ||
| await self.send_body(body) | ||
|
|
||
| async def handle(self, body): | ||
| """ | ||
| Receives the request body as a bytestring. Response may be composed | ||
| using the ``self.send*`` methods; the return value of this method is | ||
| thrown away. | ||
| Receives the request body as a bytestring. | ||
| """ | ||
| raise NotImplementedError( | ||
| "Subclasses of AsyncHttpConsumer must provide a handle() method." | ||
|
|
@@ -77,9 +78,14 @@ async def http_request(self, message): | |
| """ | ||
| if "body" in message: | ||
| self.body.append(message["body"]) | ||
|
|
||
| if not message.get("more_body"): | ||
| try: | ||
| await self.handle(b"".join(self.body)) | ||
| except Exception: | ||
| logger.error(f"Error in handle(): {traceback.format_exc()}") | ||
|
||
| await self.send_response(500, b"Internal Server Error") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this is the essence of the proposal. |
||
| raise | ||
| finally: | ||
| await self.disconnect() | ||
| raise StopConsumer() | ||
|
|
@@ -88,6 +94,10 @@ async def http_disconnect(self, message): | |
| """ | ||
| Let the user do their cleanup and close the consumer. | ||
| """ | ||
| await self.disconnect() | ||
| await aclose_old_connections() | ||
| raise StopConsumer() | ||
| try: | ||
| await self.disconnect() | ||
| await aclose_old_connections() | ||
| except Exception as e: | ||
| logger.error(f"Error during disconnect: {str(e)}") | ||
| finally: | ||
| raise StopConsumer() | ||
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding the logging call is fine I guess, but I don't think we should be adding handlers for users. That's up to them.