-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[HttpFoundation] Strange behaviour with empty session, Swift and fastcgi_finish_request function #6417
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
Comments
Another interesting point is that this only happens when |
I faced a similar issue. It looks like the session is not saved quickly enough. The browser receives the redirection without waiting the end of the process (sending the email), thanks to the use of @Drak do you have an idea to fix this ? |
I have found finally thanks to newrelic that there is a
The quick and dirty solution would be to close & write the session manually just after the last piece of the user code (maybe as a terminate event listener?) |
The issue I opened is running under apache/mod_php so fastcgi_finish_request should have no effect. Like @scourgen if I revert back to file based sessions it works fine. I tried removing the destructor that @acasademont mentioned but the issue persists. I even tried putting in a couple of calls to sleep just to slow things down and see if perhaps things were happening too quickly, but it made no difference.
|
I'm wondering if the use of I don't know the reason why this code is in the Lastly if it's not a problem with the native files handler, which drivers is it a problem with specifically? For example if it happens with the |
The issue happens when using PdoSessionHandler, I've only tried that and native files. |
I don't know if it's related but IMO there is something wrong with the PDO timing collision code which is using whole seconds, which assumes two requests cant be completed within the same second. IMO the code should be using |
Good to know, thanks. Ultimately I was going to use Redis for sessions so I'll do that sooner than later and see if it happens with that too. |
Problem still exists using Redis for sessions.
|
It would be interesting if you tried the native redis handler from this repo - there's no bundle for it yet. |
What I think is that we are facing the same problem (empty session) caused by different things. Maybe we should open some other issues? |
The issue remains using the native redis handler from drak. Switch back to the default filesystem and it works fine. Any other session handler and I lose data. |
Well it could be a PHP issue. It'a worth reporting over at PHP.net if you ask me... There have been some pretty serious session issues fixed in PHP recently and should be out in the next release. |
@jkm9000 can I ask you to hack one file in Symfony and see if the problem persists (testing both native and non-native session handlers). In https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeSessionHandler.php#L21 Line 21, just comment out just before the |
@Drak When I faced the issue, it was on PHP 5.3 with the PdoSessionHandler |
Tried changing that line, but same problem happens. I tried with both your redis handler and the snc_redis one. Initially was running php 5.4.4, have since upgraded to 5.4.10 to see if that helped. |
The it's clearly either a PHP issue, fast cgi, or Response object problem. I would report this ASAP on bugs.php.net and ping Arpad there on the issue. |
https://bugs.php.net/bug.php?id=63963 I did not see a way to ping Arpad though. |
I have sent him an email referencing it. |
Thank you. Also, I don't think it is fast cgi because it originally happened to me using mod_php / apache. |
Update - I upgraded my project to Symfony 2.2 and my issue no longer exists. |
maybe related: with php-fpm so using fastcgi_finish_request() in response::send: PAGE 1: sending bunch of mails using memory spool, redirecting to PAGE 2 adding session_write_close() BEFORE $response->send() in app.php fixed it is it a bad thing to calling session_write_close() here? |
You should really call
|
I've updated the PHP ticket with this information and pinged Arpad again. |
ok i'm pasting here cause it has some value for anyone trying to reproduce this. Also since this is reproducible why hasn't this issue the label 'Bug'? Anyways: First you have to enalbe database sessions, i did so by following this guide http://symfony.com/doc/current/cookbook/configuration/pdo_session_storage.html Then you can create 2 actions like this:
If you clear you browser cookies then each time you go to the /lol url then you get redirected to /lol2 and the session returns an empty string for session variable 'testsess' It has something to do with mail. If you comment out the line where the send() happens then all is ok. It has something to do with not writing the session in the database after the completion of the execution of the action. I have debugged the swift mail bundle a bit and it seems that when send() is called the mail is saved in memory (spool memory, uses class Swift_MemorySpool), so i suppose mails are sent after the completion of the action, after the action returns, somewhat asynchronously i suppose. It seems that something happens in the code after the action returns a redirect. This bug has 3 conditions, using mysql sessions, sending an email and then redirecting to another action. PS. using symfony 2.1.7 |
Issue is quite clear in all cases: the session is still open after a $response->send() and is only closed after $response->terminate(), i.e. on script end. The redirection is sent to the browser in $response->send() (in your case on flush(), in mine on fastcgi_finish_request()). The next page is trying to access session data wich has not yet been written because the previous script is still sending the mails in $response->terminate(). (in my case, with memcached, the session is even locked until first script end) did you try if (function_exists('fastcgi_finish_request') && $request->hasSession()) { $request->getSession()->save(); } before $response->send() ? IMO it is a php bug only if flush() or fastcgi_finish_request() is supposed to trigger the write/close session handlers, otherwise there should be a response listener to do it |
It appears this is still occurring in Symfony 2.3. I tried the various suggestions above, but none of them appeared to make a difference for me. My guess would be because I have even more chances for the race condition, due to the fact that I have some JSON files which load information as well (which means multiple simultaneous loads). I'm using the PdoSessionHandler. The behavior I get is that it loads the first page I go to, and maybe some of the other files, but it usually fails on one of the JSON pages (no Token message), and then when I try to change pages, I'm logged out. |
+1 on 2.3.1 |
+1 on 2.2.1 |
Is there an update to this issue? I'm using 2.2.2 |
It's been 11 months now since this issue was reported. Has there been no progress? I am running into this problem with MongoDB session storage under Symfony 2.3.6, nginx and PHP 5.3.10. Neither upgrading to PHP 5.5.5, nor any of the fixes proposed here worked. Is there really no new information or workaround regarding this issue? |
A quick fix is to disable spooling for SwiftMailer. I am still uncertain whether this is the actual solution, but it seems to work. I commented out the line that enables spoolingin the configuration for SwiftMailer: spool: { type: memory } By default, the mailer will not use spooling but send the mail right away: http://symfony.com/doc/master/cookbook/email/spool.html |
hi try this one this works for me, creating a custompdosessionhandler hope it helps :D http://stackoverflow.com/questions/22033564/pdosessionhandler-fosuserbundle-login |
I can confirm this happens in my case with memcached or pdo as session storage. Native file storage seems immune to this. Disabling memory spool for swiftmailer fixes it, but this is rather a dirty trick than fix. It does not satisfies me. I hope this is going to be fixed soon |
Not that this seems to need confirming, but I've just been caught out by not having flash messages appear (using 2.4 + Apache/mod_php + PDOSessionHandler + SwiftMailer memory spooling). |
Faced the same problem with both PDO and redis, PHP 5.4 + nginx / php-fpm. Symptoms are flash messages randomly not appearing, auto-connections not always working, in fact everytime you call We quick-fixed that by adding a listener on the response event and forcing $session->save(), but it doesn't seems to be a long-term solution. For information, this logic (explicitly save session on response) is already used during the tests process : https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpKernel/EventListener/TestSessionListener.php#L58 |
So my research summary of how to fix this problem is:
So all in all, we should save the session (via listener) when sending the response. This makes sure, that the next request (redirect) will have the session information available (and does not log you out). Session locking also solves this problem (but it might no be activated, e.g. due to optimistic approach). Also even if locking is activated, the auto-saving of the session via listener would prevent that the session is locked longer than needed due to long running things after sending the response. |
I'm trying to save the session explicitly after setting, Swift Mailing, and before a redirect to workaround the issue with resetting a password in the FOSUserBundle and it works on my dev environment (PHP 5.5), but not on on staging site (PHP 5.3). I'm getting the following error: |
Have php 5.5 and mongodb session storage, if I changed what @Drak say : #6417 (comment) now its everything working as expected, but hacking core is not good idea.
|
Is there any new insight on this? |
+1 |
Ok, all, what can we do to push forward a clear solution for this? All I can think of offhand is utilizing a secondary mail queue to store messages and then having another process come back in and handle sending them. Any more ideas folks? |
Would using the master version of the PDOSessionHandler, which implements locking, do the trick? |
@sabliao yes, but you should also close the session early when you don't need write access |
I've just hit the same issue trying to implement a session handler for DynamoDB. |
@gregholland Are you aware of http://docs.aws.amazon.com/aws-sdk-php/guide/latest/feature-dynamodb-session-handler.html ? It also optionally implements locking. |
@Tobion Yep, that's what I'm using. I've tried setting the locking strategy to |
…Tobion) This PR was merged into the 2.3 branch. Discussion ---------- [Kernel] ensure session is saved before sending response | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #6417, #7885 | License | MIT | Doc PR | n/a Saves the session, in case it is still open, before sending the response. This ensures several things in case the developer did not save the session explicitly: - If a session save handler without locking is used, it ensures the data is available on the next request, e.g. after a redirect. PHPs auto-save at script end via session_register_shutdown is executed after fastcgi_finish_request. So in this case the data could be missing the next request because it might not be saved the moment the new request is processed. - A locking save handler (e.g. the native 'files') circumvents concurrency problems like the one above. By saving the session before long-running things in the terminate event, we ensure the session is not blocked longer than needed. - When regenerating the session ID no locking is involved in PHPs session design. See https://bugs.php.net/bug.php?id=61470 for a discussion. So in this case, the session must be saved anyway before sending the headers with the new session ID. Otherwise session data could get lost again for concurrent requests with the new ID. One result could be that you get logged out after just logging in. This listener should be executed as one of the last listeners, so that previous listeners can still operate on the open session. This prevents the overhead of restarting it. Listeners after closing the session can still work with the session as usual because Symfonys session implementation starts the session on demand. So writing to it after it is saved will just restart it. Commits ------- b7bfef0 [Kernel] ensure session is saved before sending response
I have been hit with a very strange situation during these last 2 days. I have a custom security listener and provider that sends some emails to the user and the user's "godfather" when registering. Immediately after registering, the user is redirected to his personal area. The problem arises when from time to time, the user is logged out when redirected.
Digging into the code, I can clearly see that the session is totally empty after the redirect, so no information about the user token is present. However, when I reload the page the session is perfectly filled and the user becomes logged in again. So I assumed that the session was still not written to disk (using native php file handler) when the user was redirected!
So here is what I found out. When sending emails with the default SF mailer (Swift) some bg processing must be kept somewhere. I am using nginx + php-fpm so the
fastcgi_finish_request
function is called and the page is immediately flushed. But as there must be some kind of bg processing, the session is still not written to disk when the next request coming from the redirect hits the server and the session is empty.Comenting
fastcgi_finish_request
function call or not sending the emails seems to fix the problem so it has to be some problematic combination of those 2 things...but who knows!Any ideas?
The text was updated successfully, but these errors were encountered: