Wednesday, October 14, 2009

PHP Session write locking and how to deal with it in symfony

It has been a while since I last posted to my blog. My personal life has seen a lot of upheaval recently with a house move, a hiatus from Synaq, then back to Synaq, and the release of Pinpoint 2 to Synaq customers all playing a major role in eating into my personal time.

So as my comeback article I thought I would write on an issue that was plaguing us in development of Pinpoint and how, thanks to help from the great symfony community at the symfony users mailing list, we got it resolved.

The problem

With Pinpoint 2, a symfony based application we have developed here at Synaq, we employ quite a lot of Ajax requests in order to make the interface more responsive and less bandwidth hungry; why reload an entire page when you really only want a small sub-set of that page to change? A problem came about when we had an Ajax request running, and while this request was waiting for a response from the server, if a user clicked another link, that link would not "process" until the previous Ajax request had completed. What this meant to us was that it seemed that our requests were "queuing" instead of working asynchronously as they should.

On one particular section of Pinpoint, we have a number of Ajax requests loading at once, each one interrogating the database for data. Each of those requests "queued" behind each other, and any attempt by the user to go to another module resulted in waiting for each of these queued requests to complete before the browser would process the users interaction.

The cause

After going through all sorts of different possible fixes, none of which worked, I eventually submitted the above problem to the symfony users mailing list. The response that came back was that it probably had something to do with PHP session-write locking.

PHP manages sessions, this anyone who codes in PHP knows, and in order to ensure that session data does not become corrupted between requests, PHP will lock write access to the session files for a user while it is processing a request. This results in the following process if you have multiple requests coming through:

1. Request comes into server, and PHP locks session files.
2. Another request comes in but cannot access the session files because they are locked.
3. The first request processes, running all SQL, processing results, etc.
4. Yet another request comes in but cannot process because session files are locked.
5. The first response is finally finished, sends its output back to the calling function and unlocks session files.
6. The second request begins processing, locks session files and continues to do what it needs to.
7. Request three is still waiting for session access.
8. Yet another request comes in but ..... I think you get the picture.

The solution

The only way to resolve this issue is to force the requests to unlock the session files as soon as possible. Thankfully symfony has its own user session storage classes that make this incredibly easy.

The one problem is that you cannot release the session lock until after you have saved data into session that needs to be saved. Our solution was that for each action that processes an Ajax request, write everything as soon as possible to session that needs it and then unlock session to allow any other request to begin processing.

We hit a roadbump. Using symfony's $this->getUser()->setAttribute() command to store session data, we then used PHP's session_write_close() to force PHP to let go of the lock and let the next request begin work. This did unlock session but we noticed that all the data allocated to session using $this->getUser()->setAttribute() was not saved.

After a little exploration of the symfony classes we noticed that when the setAttribute() method is used, in order to speed up processing, symfony does not immediately write to the global PHP $_SESSION variable. Instead it keeps those values in an array until the end of script execution and only then writes to session. Using PHP's session_write_lock() we pretty much made it impossible for symfony to do this because to prevent session data from losing concurrency, PHP does not allow a script to write to session if the session was unlocked.

We did, however, find another method: $this->getUser()->shutdown(). This forces symfony, when the shutdown() method is called, to write session data into $_SESSION and then it also runs session_write_close() itself.

The end result

We now have actions that process Ajax requests and once all data has been sent to session using $this->getUser()->setAttribute() we run the $this->getUser()->shutdown() method. The difference was incredible and has actually speeded up our entire application a ton.

One thing to be careful of however. You do need to be sure that you call that shutdown() command at the right time, because if you call it too early, session data will not get saved and PHP will just ignore it. We had to reshuffle some code so that all the database calls and data processing functions were run after shutdown() as well.

Thanks again to the symfony community for helping to point this out and hope this helps others who may have the same issue as well.


  1. I spent 2 days on this problem, except for me the query was performed by a flash app, and I spent too much time believing that the problem was client side...
    I can't thank you enough for this fix :). You literally saved my day, I can now go back to my normal work.

    Thank you again.

  2. Thanks, it was very interesting to read, now i'll know what to do :)

  3. Muchas gracia por comentar tu experiencia, pues a mi también me has salvado el día ;) nuevamemnte muchas gracias
    Thank you very much for commenting on your experience, because I too have saved the day) again thank you very much

  4. Great post about a hard-to-detect issue !

  5. Great Post! this work for me too but in development mode i cant write user session!!

  6. Thanks, I also faced this phenomenon, you saved a lot of debugging time :)

  7. Thank you! I develop an extremely data heavy application and this problem was become a serious performance issue. Traces in new relic going back 45 seconds before allowing the next request, for example. Now everything is incredibly snappy! I really appreciate this.

  8. Great post . It takes me almost half an hour to read the whole post. Definitely this one of the informative and useful post to me. Thanks for the share. I also provide this service plz visit my site php development in delhi Elesoftech is a leading offshare web development.

  9. Great and awesome post It takes me almost three days to read the whole post. But it's a very informative and useful for me.
    php training in chandigarh

  10. Thanks For Sharing. It IS very helpful For Everyone ....
    If You Are Looking Best PHP training in chandigarh click here

  11. This is most informative and also this post most user friendly and super navigation to all posts... Thank you so much for giving this information to me.. 
    Best Devops Training in pune
    Microsoft azure training in Bangalore
    Power bi training in Chennai

  12. I would really like to read some personal experiences like the way, you've explained through the above article. I'm glad for your achievements and would probably like to see much more in the near future. Thanks for share.
    Selenium training in Chennai
    Selenium training in Bangalore
    Selenium training in Pune
    Selenium Online training

  13. I’ve desired to post about something similar to this on one of my blogs and this has given me an idea. Cool Mat.

    Python Online certification training
    python Training institute in Chennai
    Python training institute in Bangalore

  14. This post is much helpful for us. This is really very massive value to all the readers and it will be the only reason for the post to get popular with great authority

  15. The article is so informative. This is more helpful for our
    software testing training online
    best selenium online training in chennai. Thanks for sharing

  16. nice blog
    get best placement at VSIPL

    digital marketing services
    web development company
    seo network point

  17. This is really an awesome post, thanks for it. Keep adding more information to azure training in bangalore

  18. This is really an awesome post, thanks for it. Keep adding more information to this.mulesoft training in bangalore

  19. Really it was an awesome article,very interesting to read.You have provided an nice article,Thanks for sharing.salesforce developer training in bangalore

  20. Being new to the blogging world I feel like there is still so much to learn. Your tips helped to clarify a few things for me as well as giving.salesforce admin training in bangalore

  21. Linking is very useful have really helped lots of people who visit blog and provide them use full information.servicenow training in bangalore

  22. Your articles really impressed for me,because of all information so computing training in bangalore

  23. Good to know about the email list business. I was looking for such a service for a long time o grow my local business but the rates that other companies were offering were not satisfactory. Thanks for sharing the recommendations in this post.hadoop training institutes in bangalore

  24. Thank you so much for the great and very beneficial stuff that you have shared with the world.

    Bangalore Training Academy located in Bangalore, is one of the best Workday Training institute with 100% Placement support. Workday Training in Bangalore provided by Workday Certified Experts and real-time Working Professionals with handful years of experience in real time Workday Projects.

  25. Such a great information for blogger i am a professional blogger thanks…

    Became An Expert In Selenium ! Learn from experienced Trainers and get the knowledge to crack a coding interview, @Softgen Infotech Located in BTM Layout.