Reputation: 3312
Is it possible to send a request using Symfony HTTP Client without awaiting the response?
In my use-case some requests to my app should notify a third-party service. The response of that service is irrelevant, and the notification is also not crucial. It doesn't matter if it fails due to a timeout or something similar. But these requests shouldn't delay my app's response. I want "fire and forget".
I use the following controller action to experiment:
class MyController extends AbstractController
{
#[Route('/', name: 'test', methods: ['GET'])]
public function fireAndForget(HttpClientInterface $http): Response
{
$res = $http->request(
'POST',
'https://httpstat.us/201?sleep=5000',
['json' => ['x' => 'y']]
);
return new Response('done');
}
}
Using the debugger, I can step immediately to the return
after the request. But the response isn't returned before the request has completed.
I'm using Symfony 6.0 and have curl extensions installed, so Symfony HTTP Client uses CurlHttpClient
under the hood.
Upvotes: 4
Views: 2644
Reputation: 47329
If you are really not interested in the response during the incoming request lifecycle, you'd better decouple the outgoing HTTP request, and do not perform it during the request. Simply store in some sort of job queue and process it later.
Any HTTP call will be blocking at some point, so you might as well take it somewhere else. And that's without taking error responses into account, which could happen as well and will trip things like Symfony's HTTP Client, that does not like very much receiving responses in the 300-599 range.
In the end, if the outgoing requests are not relevant for the response, and should not "delay your app's response", then they simply shouldn't be executed there at all. Call them somewhere else.
Decoupling via a some sort of message queue (either using a fully fledged queue package like Symfony Messenger, or simply storing the "tasks" anywhere else and having a script go through them and marking them done) would be the most reasonable way to go.
Any request you make through will be waited upon. You can tweak the timeout by calling withOptions()
on the HTTP Client, to wait very little time before timing out... but, it would still wait that "very little time".
And you would also need to handle the exception when the client times out (or whenever there is actual non-200 response). You end up with "fire and do quite a bit of work trying to forget we've actually fired". It's not worth the hassle, and it is poor design in any case.
Upvotes: 5