PHP sessions are not designed for websites that use AJAX heavily and have multiple concurrent requests. This article will explain how we get rid of this behaviour.
I’m not here to explain how sessions work in php, if you want more information you can look at http://php.net/manual/en/session.examples.basic.php.
But by default PHP uses file based sessions. When a process accesses a session, it opens the session file and puts a lock on it. Until the process is finished, the lock remains and the session cannot be accessed by another process. By default, this is a good thing because it avoids concurrency issues on the session.
But the main issue with this behavior concerns websites that use AJAX heavily and have multiple concurrent requests. Those requests cannot run in parallel and are serialized.
Here is an example:
In order to deal with it, the standard practice in PHP is to call
session_write_close() as fast as possible during the code execution. This leads to several bugs, side effects, etc…
We have decided to work around this issue and we have developed a new session handler. The idea behind this new session handler is that most of the time, when 2 processes access the session, they only read it, and if there is a write, there is generally no conflict in the session changes. Hence, we decided to build a session handler that is optimistic and assumes everything is going to be all right. And if things go wrong, the session handler takes the same strategy as any versioning tool to resolve the conflict.
To reach this goal, we release the lock on the session file as soon as possible.
Here is an example of the new workflow :
So with this approach the session is locked at the beginning and at the end of the execution of the php code. If the session has been modified by one (or many) of the processes, we have to resolve potential conflicts. So like any versioning tool we make a 3 ways comparison between the first session read (we will call this session ”base”), the second one (we will call this session ”their”), and the current session (we will call this session ”mine”).
Comparison is made on a key by key base. So if script A modifies key « user_id » and if script B modifies key « last_access_time », there is no conflict. Another way to say this is that session granularity is made on a key level.
With this convention we will get a conflict when:“
$base != $mine && $base != $theirs && $mine != $theirs“. By default we will throw an exception (SessionConflictException) when this case happen, but we give the user the ability to set rules in order to resolve this kind of conflict.The rules are defined in an array where the key are used to identify which rule should be used for a specific session attribute. Does it work ? Yes ! We used this new session handler on a page with a high number of Ajax requests (a lot of data in Ajax grids in a dashboard) and managed to speed up the overall load time of the page by a factor 3. Of course, this new session handler is open-source, and since it targets low-level PHP session interfaces, it can be used in any PHP framework. If you want to try this new session handler, or want more technical information just visit https://github.com/thecodingmachine/utils.session.optimistic-session-handler.