Skip to content
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

After BufferHandler::close(), ignore further close() calls #1837

Closed
wants to merge 1 commit into from

Conversation

tstarling
Copy link

BufferHandler overrides the parent destructor, but it's possible for
close() to be called from a destructor anyway, late during request
shutdown, if the BufferHandler is put in a GroupHandler.

So, avoid flushing the logs twice by ignoring the second call to
close().

Downstream bug https://phabricator.wikimedia.org/T288624

BufferHandler overrides the parent destructor, but it's possible for
close() to be called from a destructor anyway, late during request
shutdown, if the BufferHandler is put in a GroupHandler.

So, avoid flushing the logs twice by ignoring the second call to
close().

Downstream bug https://phabricator.wikimedia.org/T288624
@Seldaek
Copy link
Owner

Seldaek commented Oct 27, 2023

Interesting issue.. But if flush() triggers an issue it means something was logged between close() and destruct. Otherwise flush would have nothing to flush and it'd be a noop. So that sounds a bit concerning to me, and IMO should be investigated on your end?

The other weirdness is that in __destruct we do catch exceptions coming from close(), so in theory this should not error? I'm not sure where the error comes from? I guess it might be because it is a warning and not an exception. Perhaps the more appropriate fix here would be to register a temporary noop error handler in Handler::__destruct?

I am digging in here because I don't like the proposed fix as it makes the handler unusable after close is called, and ideally handlers should keep functioning/reopen if logs arrive after close.

@Seldaek Seldaek added this to the 2.x milestone Oct 27, 2023
@Seldaek Seldaek added the Bug label Oct 27, 2023
@tstarling
Copy link
Author

Interesting issue.. But if flush() triggers an issue it means something was logged between close() and destruct. Otherwise flush would have nothing to flush and it'd be a noop. So that sounds a bit concerning to me, and IMO should be investigated on your end?

Probably. It's a big application, with a lot of developers, I don't think we can enforce this as a policy. Maybe we can call close() a bit later. But the destructor is too late -- the bug shows that you can't expect flush to work reliably during zend_objects_store_call_destructors(). Objects are destroyed in a random order so you can't safely call any method or use any property of an object other than $this.

The other weirdness is that in __destruct we do catch exceptions coming from close(), so in theory this should not error? I'm not sure where the error comes from? I guess it might be because it is a warning and not an exception. Perhaps the more appropriate fix here would be to register a temporary noop error handler in Handler::__destruct?

Yes it's a warning.

Trying to ignore all the weird and broken things that are going on during request shutdown is not a very satisfying solution. If an app really was relying on flush() being called from __destruct(), those warnings would be the only indication they have that some or all of their log events are being thrown away.

I don't mind throwing away log events from very late in request shutdown, but we're buffering events, so there's a risk of losing the whole buffer.

I am digging in here because I don't like the proposed fix as it makes the handler unusable after close is called, and ideally handlers should keep functioning/reopen if logs arrive after close.

I see that it contradicts the HandlerInterface::close() doc comment which says that handlers should reopen after close. So feel free to close this PR.

An alternative might be to add a method which causes the handler to temporarily ignore log events. Maybe something like

interface HaltableInterface {
    function halt();
    function resume();
}

@Seldaek
Copy link
Owner

Seldaek commented Apr 12, 2024

Yeah I'm sorry but I don't quite see what can be done here without potentially causing more problems for others so I think I'll have to close.

@Seldaek Seldaek closed this Apr 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants