Colin-b/pytest_httpx

Async callbacks should be allowed to delay some responses while not blocking the async loop

Closed this issue · 7 comments

Hi,

For a project that makes a lot of async requests I would like to emulate the effect of slow http responses. AFAIK that is currently not supported in this library. To me it would be useful to have an option to specify a delay in (micro)seconds.

I would be happy to provide a PR if this is something you would consider merging.

Cheers

That's one of the purpose of the dynamic response: https://github.com/Colin-b/pytest_httpx#dynamic-responses :)

You can implement whatever logic you want before returning the response. So a time.sleep would work I guess

I'm not sure if that will work because the callback is always sync, there is no async callback right?
So lets say that I'm making async 2 responses, one directly after the other. The first one I want to delay with 0.5sec and the second one without delay. Doing a sleep in the sync callback will delay both responses

Indeed, you would have to use asyncio.sleep but as callbacks are not async, you can't. #38 and #43 did had the same requirement but managed to do it without async callbacks.

Just to make sure, can you confirm that time.sleep is blocking the asyncio loop?
Also, can you confirm that using unsync on the callback (while using asyncio.sleep inside) does not work (as it should be another event loop)?

Based on those 2 results we will now what to do.

Thanks for your feedback

Regarding your first point:
I've created a small gist to test if time.sleep blocks the event loop, and indeed this is what is happening. This is also what the docs suggest. the whole thread will sleep. And ofc everything is running within one thread.

I've not yet tried the unsync library yet but what I understand about it is that it will run basically the async function in an event loop on another thread. So I don't see how pausing another thread will slow down returning the response in a non-blocking way (either the callback has to wait for the other thread to finish the sleep before returning the response, making it a defacto blocking call. Or the callback would do the sleeping part in another thread and immediately returning the response).

To give you a bit more context about what I'm trying to achieve: I have a system with a set of async workers making http requests. If one of the servers is giving slow responses they should use another service. I'm trying to setup some tests to verify the behaviour of the system.
Another test I'm developing is about measuring the throughput of the system when some of the host become slow. For this I need to have async callbacks.

In general I think that for any http test helper it is super useful to emulate slow responses. And especially for httpx it would be helpful to at least accept async callbacks, since they offer an async api (although my preferred option would be to add a deloy as an option to the API). I'm happy to help with this this (accepting async callbacks and optionally adding delay as parameter to the API).

I do agree, I was hoping for some low hanging fruit in case my understanding of async was incorrect ;)

I have already an implementation idea in mind, basically I would like to not change anything from your perspective, except that add_callback would accept async functions. I think that's achievable with minor impact on code base (I hope so anyway). However It will involve a bunch of new test cases , so i'll put it in my backlog.

I hope to find some time to dig into this soon enough

Release 0.21.1 is now available on pypi and allows you to register async callbacks. You can also find a sample in documentation registering an async callback simulating network latency.

Thanks a lot Colin! Really appreciate the fast responses and merge of the new functionality. Thanks for maintaining this package :)