Detect when client closes a connection from aiohttp request handler - python-asyncio

I have a long running request during which I push data down to a client as it is received. However, the request requires some resources that are created server side that I'd like to clean up whenever the client disconnects. I've looked through the docs, but I can't seem to find a way to detect when that happens. Any ideas?

This isn't super obvious looking at the docs, but the key here is that the asyncio server will throw a CancelledError into handler coroutine when the connection is closed. You can catch the CancelledError wherever you wait for an asynchronous operation to complete.
Using this, I clean up after a connection with something like this:
async def passthrough_data_until_disconnect():
await create_resources()
while True:
try:
await get_next_data_item()
except (concurrent.futures.CancelledError,
aiohttp.ClientDisconnectedError):
# The request has been cancelled, due to a disconnect
await do_cleanup()
# Re-raise the cancellation error so the handler
# task gets cancelled for real
raise
else:
await write_data_to_client_response()

Related

FastAPI WebSocket

I have a background process, which does a file preparation after receiving a file on the endpoint.
I have a websocket defined also:
#app.websocket_route("/ws/{uid}")
async def websocket(websocket: WebSocket):
await websocket.accept()
await websocket.send_text("Hello")
await websocket.close()
This solution sends the Hello text when the user connects.
But I want to send the text only after the background process is finished.
So my aim is to define a websocket in other function and from there send the text to a websocket.
How can i do it?

What is the right way to dubug context cancellation for a grpc call?

I am working on an go application, that uses gin to serve the rest APIs.
I 4 of my handler functions for the APIs call a goroutine which makes a gRPC call. A strange thing i see, all the grpc calls for one of the handler fails with context cancelled while the other 3 succeed.
Looking at the logs, i noticed that my API returns before the goroutine is executed. Could it be possible that gin cancels the context after the API returns?
The context is propagated from the handler function to the goroutine through a couple of intermediate calls.
The error that i see is rpc error: code = Canceled desc = context canceled
How can i debug this? Does gin cancel the context once it returns the response?
Does gin cancel the context once it returns the response?
The docs for Request.Context() (gin uses http.Request) say:
For incoming server requests, the context is canceled when the client's connection closes, the request is canceled (with HTTP/2), or when the ServeHTTP method returns.
So, yes, the context is closed when your handler (effectively the ServeHTTP method) returns (see here). The context would also be cancelled if the connection dropped for another reason (network issue, or even your server shutting down).
The right way to handle this really depends upon what you want to achieve:
In many cases the correct behaviour is to cancel the RPC calls when the context is cancelled. For example if you are retrieving info needed to fulfil the request then cancelling those requests may save resources.
If you are triggering calls that must complete then pass in a context.Background() (or another context not directly tied to the request).
How can i debug this?
Look at why your handler is returning before all RPC calls complete; if that is what you want then you will need to use a different context (but remember this probably means you are returning an OK response code when you don't actually know yet if the entire process will be successful).

Consequences of not awaiting

I have a .net webapi that has some code to send emails.
public async Task CheckOut(CheckOutData checkOutData){
...
...
...
//What are the risks if I remove the await
await SendEmail(checkOutData);
...
...
}
public async Task SendEmail(CheckOutData checkOutData)
{
try{
...
...
...
}
catch (exception ex){
//log Error
}
}
I have setup logging in the SendEmail code. My question is, if I remove the await, is it possible for the thread to be killed and the email not being sent if the execution completes before the SendEmail completes?
Am I safe if I remove the await? I am willing to accept that an exception will be swallowed, it will be logged.
The email will be sent unless the entire process stops.
Regarding threads, we can divide SendEmail to two parts:
SendEmail
// Code that will run on the calling thread. This is the code that will prepare the data and send it to the hardware.
// Code that will run on a thread-pool thread. This is the code that will run after the hardware will finish sending the message.
The first part of the method will hold the original thread so the thread will not be released before it will finish. The second part will run on a thread-pool thread so it doesn't matter if the original thread was released.
EDIT:
If you are hosting your application on IIS, the app domain maybe recycled so it's not advised to run code that last the request. It's described in this blog post https://blog.stephencleary.com/2012/12/returning-early-from-aspnet-requests.html
In the self-hosting case this feature doesn't exist (Application pool recycling with Selfhosting a ASP.NET application). So you can just run a long running process by using Task.Run
Long running task in ApiController (using WebAPI, self-hosted OWIN)
So in the self hosting case you can avoid the await. The part of your method that you won't wait for won't be killed. As in the Task.Run case described above.
Hope this helps

How to allow discord bot to respond to webhook. Python. Discord.py

I have a problem trying to get a webhook to interact with a bot
For some reason, the bot doesn't respond to commands initiated by the webhook
Is there a way to make sure it initiates?
It works normally otherwise
My command:
# registering new commands that can be called by the flask webhook
#client.command()
async def new_message_received(ctx, trade_hash: str = ''):
print(f'New Trade Received! {trade_hash}')
paxful_cogs = client.get_cog('Paxful_Cogs')
await paxful_cogs.new_trade_received(trade_hash=trade_hash)
await ctx.send(f'{trade_hash} executed.')
print(f'Trade Done Execution! {trade_hash}')
My webhooks are sent successfully, but the bot does not respond to them.
Bot Responds to Me, but not to webhook.
Okay, figured it out with a lot of help from the python discord server.
#client.event
async def on_message(message):
# Manually get the invocation context from the message
ctx = await client.get_context(message)
# Verify that the context has a command and can be used
if ctx.valid:
# Invoke the command using the earlier defined bot/client/command
await client.invoke(ctx)
https://i.gyazo.com/d23edb65efeeaa834c5de33d70f00484.png
Basically, we're overriding the on_message fx, checking to see if the message matches our prefix/command structure with ctx.valid and then forcing the command to be processed with client.invoke(ctx) regardless if it's from a bot/webhook or not.

Calling dispatch in subscribe in Autobahn

I am using Autobahn and I have an implementation-specific question.
I am trying to figure out how to send a notice to all connected clients (including the newly subscribed client) upon a client subscribing to a topic. Here's the code (edited down for clarity):
#exportSub("", True)
def subscribe(self, topicUriPrefix, topicUriSuffix):
topic_uri = "%s%s" % (topicUriPrefix, topicUriSuffix)
self.client.dispatch(topic_uri, {"msg":"WTF"})
return True
Yet, I'm not seeing the newly subscribed message receive this dispatch. The dispatch call is returning None.
What's happening here?
I figured this out. A client must first be subscribed to a topic before receiving a message sent via dispatch(). This means that the dispatch() cannot be called inside subscribe if one expect the subscribing client to receive the message. I worked around this problem by building a simple message queue and calling dispatch on the protocol instance for any queued messages.

Resources