One of the challenges of web application is the HTTP way of request and response. This means the client (typically a web browser) sends a request to the web server, which in turn sends a response back. All the interaction between the user interface in the browser and the software’s business logic is over the network.
When a user opens a web browser and decides to access a particular web application, session is started. A session is a simply a collections of requests that happen over some time. The session starts or gets created on the web server upon a new first request and dies when after the last request, which usually times out.
A business transaction is a set of multiple actions or set of requests and responses that perform some collative work. For example, a business transaction of buying a flight ticket might include selecting a time of departure and return, destinations and so on, selecting flights from a list of search results, typing in passenger informations and payment details and confirming the purchase.
Contrast this with system transactions which operate on the database level. For example, when accessing the database a software program might read a row in a table, update the row, and then add a new row to another table. At the beginning we start a transaction and in the end we commit. If something fails we roll all the changes back. This is common in relational database models and referred to as ACID properties.
Business transactions operate on a higher level and usually involves the user’s actions. So the problem we have to solve is how to successfully complete a valid business transaction when all the requests go back to the user and depends on what the user does.
The solution is to maintain a session. Think of the session as a the time period from the first request to the last request. Also think of the session as a data collection that maintains a state. Session state is the data that we keep to track the users actions in a business transaction.
The web server is responsible for maintaining the session. This is part of the context of the web application. The scope of the session is from the first request to the last requests. The same session exists between multiple requests. This is referred to as session scope, the time period which the same session exists. As the developer of the software for the web application we get access to some information about the session in the context, usually be calling a function that returns some session object. This session object and session state is not the same.
Now if we as web application developers need to maintain information on what the user is doing, for example keep track of the selected flight we need to store that information, the session state, somewhere between the requests.
Session state is different from record data. The latter is persisted data usually stored in a database and will survive the session. It will also survive if the web application is restarted due to crash or maintenance. Thus session state is temporary while record data is permanent, at least until deleted or changed. Another difference is that record data must have data integrity thus be valid in the database. The session state can have incomplete data.
Consider the fight ticket example. When a flight ticket is bought it is stored in a database table and must contain all the information that such a ticket must have. The session state might have parts of the ticket information at any give time since the user still needs to make selections. Only in the end upon confirmation is all the information available and a proper ticket can be created.
One problem we face as software designer is where to store the session state. Basically there are three possibilities: on the client, on the server or in the database. We can combine any of these together so one does not eliminate the other.
Client Session State
In this design pattern we store the session state in the client.
When we have simple requirements and the state is small, storing it in the client is a good choice. If we want to have stateless servers and avoid and database bottleneck, we can achieve high scalability using this pattern. One way to implement this is to use HTTP cookies. The web server supports cookies and we can used those to keep the state. REST is another approach. It basically is an approach to maintain the state within the requests.
The benefits of this pattern is that it is simple and keeps the server stateless. The drawbacks of this approach is that the state must be small. If it gets big we suffer network latency by sending the state with the request and getting it back. Another drawback is that if we client crashes the state is lost. There are also some security issues as we are sending information multiple times over the network. This can of course be encrypted but that adds another layer of complexity. Web browsers store cookie data in some temporary files on the users computer.
Server Session State
In this design pattern we store the session state in the server.
This is perhaps the simplest of the session state patterns to implement and is probably the most common. The motivation is that we must keep track of the user’s actions through some business transaction. Storing this on the server is relatively easy. Simplest way is to access the session object from the web server. This is an internal object that the web server creates and maintains. Usually the session object has some methods for putting and getting data. We can add our session state to this session object.
Consider the following example. A user is logged in. We know that a User object is stored in the web servers session object. So get get the session object and ask it to return the User object. Some other part of the web application has stored it there upon user login. If there is no such object we redirect the request to another part of the application, for example a sign up form. Now let’s suppose the user was selecting a flight just to continue our flight example. We can then create a Flight object with the information we have and put that into the session. Upon next request we can access this Flight object and change it or use it in some ways.
The benefits of this approach is that it is simple with the support we have from the web server. This pattern work well if the users is building up data one request at a time, for example making choices, or adding products to a shopping cart. Then in the end, upon some confirmation the state is complete and then sent to the database to become record data. For example a flight ticket or a shopping order. Until the last step the state is incomplete and just kept in memory on the server between requests.
The session state can be objects like a Java object or it can be serialised in some form, even XML. As developers we need to be able to place the state in the session object and we need to know how to get it. Although the use of the web server’s session object is the most common, it is not the only way to store the session on the server. We can maintain a file on the disk or we could have a local database.
The drawbacks are that the client becomes dependent on the server. This limits scalability as we must now make sure clients use the same server. This is know as server affinity. Today server affinity can be solved by hardware boxes like load balances so it may not be a developer problem. Another drawback is if the server crashes or is taken down, the session state is lost. Using the servers memory is another limitation. If the session state is large, we can only have so many users on a given server.
Another issue we must address is the possibility that he user decides not to continue. Since we are just getting series of requests we have no guarantee that the next one will come. In this case, the web server supports session timeout events. These are sent when a specific time has passed from the last request from the same client. In this case, we as developers must register for this event and clean up.
Database Session State
In this design pattern we store the session state in the database.
Web Applications that don’t have some form of a database or persistence store are rare. When we need to store session state the database is a good candidate. We can store the state in a temporary or pending tables so it is kept separate from the record data. Another way is to put the state in the record data tables but mark them specifically.
This pattern is useful in applications where the user is working on data over multiple sessions. For example, consider a grant proposal application. Filling out multiple pages of information might take some time. You start filling out a form, but then you need to go and gather more information, so you come back the next day. In this case using a database session is the best choice. Even if the session state is in the database it is still a temporary session data not proper record data.
The clear benefit of this pattern is that it leaves the servers stateless and thus multiple servers can be deployed for maximum scalability. The database is of course a bottleneck but this works for most application except those with extreme loads. Another benefit is that the data persists and thus taking down servers is not a problem.
Just as with the server session, incomplete session state must be clean up. If we use the database just like a server we can use the server session timeout even to clean the session data from the database. However, if we want to allow a new session to continue using the same session data using some form of retention routines might be better choice. These routines execute for example daily and scan the database for incomplete data. Thus we might want to put expiration date on session state and delete it if user does not return.