-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
Shutdown kernel for surrogates and handle as master request #34688
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
Closed
Closed
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this makes sense:
Kernel::handle()
callsKernel::boot()
, which then calls$this->container->get('services_resetter')->reset()
, which is for that: resetting the container to a state that allows one request to not leak to the next one.If there still is a leak, that's a bug with some services that aren't reset properly.
The proposed approach will kill performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Well, the performance kill is not really an argument for me, it's the same if you use Varnish (actually even worse because of the PHP startup time). Anyway, if resetting the services is the way to go then I'm fine with that. Can you explain to me why we have a
$sessionUsageStack
in https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php#L67 then? As far as I could tell this is to count the usages across multiple master requests which should never happen except for theHttpCache
case? Does it? If not, then resetting the stack (which doesn't need to be a stack anymore then) would be more consistent with the rest of Symfony or am I wrong here?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AbstractSessionListener doesn't know anything about HttpCache - and shouldn't. So it has to stack to keep being agnostic, isn't it?
Should the services resetter be called between virtual ESI requests? I think so :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I agree it shouldn't know about HttpCache. I don't know if it has to keep the stack to be agnostic. We could argue the same for every other service. Why is there the
ResetInterface
in the first place then? :)Yes, it should. That's why I proposed to actually shutdown and boot the whole kernel again. I know it's not performant but in fact that's exactly what happens when you use Symfony behind Varnish. You have a completely separate PHP process for every single ESI request. ESI has to be chosen wisely, that's the nature of ESI fragments 😊
But I'm also fine calling the services resetter, although in #34688 (comment) you said it's already done?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't trust me, trust the code :)
I'm not sure we get inside this "if", so maybe we should do a direct call to the resetter.
symfony/src/Symfony/Component/HttpKernel/Kernel.php
Line 101 in ae00ff4
Shutting-down the kernel is no-go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, so here are my findings. I did test a simple site with one fragment, so this:
Here's what's happening:
Kernel::handle()
for/about-us
Kernel::boot()
for/about-us
.$this->requestStackSize
is0
and$this->resetServices
isfalse
. Note that afterboot()
$this->resetServices
is set totrue
so the next time when we boot, it will betrue
.AbstractSessionListener::onKernelResponse()
detects asessionUsageIndex
of10
in my case. Compared toend($this->sessionUsageIndex)
which equals0
it differs, so the response is turned into aprivate
response correctly.HttpCache::forward()
is called which callsKernel::boot()
. Because of$this->resetServices
being set totrue
in step 2, services are now correctly reset and the service resetter is called.$this->resetServices
is set tofalse
so it's not done again.Kernel::handle()
again because that's called byHttpCache::forward()
after callingKernel::boot()
in step 4. The services are not reset because$this->resetServices
is nowfalse
but it's set totrue
again for the nexthandle()
call.AbstractSessionListener::onKernelResponse()
detects asessionUsageIndex
of16
now in my case. Compared toend($this->sessionUsageIndex)
which equals10
now, it still differs, so this response is turned into aprivate
response as well.So to sum up I think we can state the following things here:
sessionStack
logic in theAbstractServiceListener
could be implemented without the complexity it has now by using theResetInterface
like all the other services in Symfony for reasons of consistency. I even think, counting theusageIndex
(which again brings a lot of complexity in my opinion) is not needed. The$session->hasBeenStarted()
implementation would've been enough imho. I don't know why exactly this was implemented. Maybe there are other reasons that go beyond resetting between surrogate requests.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i have some very vagure recollections that in the beginning of symfony 2, there were problems where people accidentally started the session e.g. by just checking if there is anything, as that auto-created the session. at least at the time, the answer was to first check if a session exists at all. maybe this behaviour is a DX to help badly programmed applications that accidentally start a session to not break all caching? (though if that is the case, a phpdoc on the usageIndex to explain this would be a good idea)
does git blame or history somehow help figuring out when this was introduced?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Except supposed complexity, is there anything to fix then?
Otherwise, not sure we should care :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no that's not related, you still need to check
Request::hasPreviousSession()
for that.As far as I noticed, the counter is also increased if the security token storage is accessed, even if the session is not started.
Well there's so much complexity, we (@Toflar, me and other Contao) devs are banging our head at why this isn't working as expected and why it's so complex. Also, tracking the security token storage state inside a session is completely non-obvious and makes no sense except for it works that way.
I don't think there's an urgent fix needed here, but I'd love to see some DX improvements. Using the well-known/very clear
kernel.reset
to check the session usage is certainly one step in that direction.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah we can close this because functionality-wise it's fine. Just DX is horrible tbh.