-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
[Discussion] Reset FingersCrossedHandler on stateful runtimes #1885
Comments
This is the same case as we discussed on Symfony discussions. Monolog as well as Symfony doesn't know your web app is a long running script. You have to jump into request-response cycle and reset given service on your own. |
This is not the same case.
This is the main point here. As you pointed out in Symfony discussions, the handler is already marked to be reset on terminate. But that doesn't fix the issue of having the same logger for every request. |
Look at the following code inside an example controller: #[Route('/slow', methods: ['GET'], format: 'json')]
public function slow(): Response
{
$this->logger->info('Slow - logger id', ['id' => spl_object_hash($this->logger)]);
$this->logger->debug('Log de debug antes do sleep');
sleep(10);
return $this->json('Ok');
}
#[Route('/fast', methods: ['GET'], format: 'json')]
public function fast(): Response
{
$this->logger->info('Fast - logger id', ['id' => spl_object_hash($this->logger)]);
$this->logger->error('Erro solo que não deve ter mais nada');
return $this->json('Ok');
} If you access the slow route, it's going to add info and debug logs, but if you have fingers crossed configured to only log errors, nothing should be logged. But if, while the slow endpoint is running, you access the fast one, you'll see the logs from the slow request, because the logger is the same. Hence the following:
|
Same goes for the following: #[Route('/slow', methods: ['GET'], format: 'json')]
public function slow(): Response
{
$this->logger->info('Slow - logger id', ['id' => spl_object_hash($this->logger)]);
$this->logger->debug('Debug log before sleep');
sleep(10);
$this->logger->error('Error log that should come after the debug');
return $this->json('Ok');
}
#[Route('/fast', methods: ['GET'], format: 'json')]
public function fast(): Response
{
$this->logger->info('Fast - logger id', ['id' => spl_object_hash($this->logger)]);
return $this->json('Ok');
} The |
Does your stateful runtime allow to handle more than 1 concurrent request per process? Or does it share memory between processes (or threads depending on runtime architecture)? If any of these is true then you indeed have a problem (like it is in Java or C# applications I believe). |
It's not mine 😅 but yes, Swoole does allow that.
That is also possible in Swoole, yes.
Yep, that's why I'm bringing up the discussion so we can figure out a way of having our PHP applications running on those runtimes safely. :-D |
The only way to avoid issues when running concurrent requests running in a runtime is to have no stateful services being shared between those requests. This would require either having no stateful services at all (but the whole point of a FingersCrossedHandler is to be stateful by buffering log entries until activation happens) or to have separate instances per request being handled (in the case of Symfony, this would end up meaning booting separate kernels for each concurrent request so that they have separate containers). |
Yeah IMO if you share a single container between multiple concurrent requests in one process you're gonna have bigger issues than the FingersCrossedHandler. Like what happens when an entity is half-modified in one request while another flushes doctrine changes? Doesn't sound very ACID compliant :D So yes if you run concurrent requests in a single process I would say you need to have at least a fresh container per request, which would instantiate a new fingers crossed handler as well. You can still reset and reuse the container once done with that request so you'd have a pool of containers each running a single request at a time, if that really saves enough cycles to be worth the risks of state pollution between requests. |
While looking into Symfony Runtime, I was thinking about FingersCrossedHandler. I assume it's always going to hit the buffer limit and I thought about writing an event listener for the
kernel.terminate
event and always reset the logger, but that would not reset only the logger for that request, since the logger is now global.So with multiple requests, I might have the logger being reset and the next entry would be in the fingers crossed action level for a different request, causing a problem.
But currently, if I'm not mistaken, one request can build up debug logs for one request and if another one triggers the action_level, all the requests logs are going to be sent to the nested handler, not just the ones for that request.
I was wondering if there is a way of scoping the logger for each request and, doing so, we could have FingersCrossedHandler implemented safely in stateful runtimes such as Swoole, ReactPHP, FrankenPHP, etc.
The text was updated successfully, but these errors were encountered: