Users of an application on a standalone Tomcat are logged out whenever the server restarts or the WAR is redeployed. How does Tomcat's default session manager treat sessions across a stop and start, and what makes them disappear anyway?
answer
- in-memory map by default
- serialized only on a clean stop
- one unserializable attribute loses the session
- redeploy is not restart
basics
~20 sTomcat's StandardManager keeps sessions in memory and, on a graceful stop, serializes the active ones to a file under the work directory, reloading them at the next start. A crash, a non-serializable attribute, a redeploy that clears the work directory, or a disabled pathname all defeat it.
solid answer
~50 sBy default a context gets a `StandardManager` holding sessions in a map in the JVM's heap. On an orderly stop it serializes the active sessions to `SESSIONS.ser` under `$CATALINA_BASE/work/<engine>/<host>/<appname>/` and reads them back — deleting the file — when the context starts again. It fails quietly in several ways: after a `kill -9` or an out-of-memory kill nothing is written at all; any session attribute that is not `Serializable` makes that session unrestorable and Tomcat logs it; a redeploy wipes the context's work directory and replaces the class loader, so classes for the serialized attributes no longer match; and many production configurations set `<Manager pathname=""/>`, which turns persistence off deliberately. If sessions genuinely must survive, that is a design decision: keep them out of the JVM in an external store, or configure a `PersistentManager` with a store, or run a cluster with session replication and mark the application `<distributable/>`.
code
xml · 4 lines<Context>
<!-- Disable shutdown persistence: sessions live only as long as the JVM -->
<Manager pathname=""/>
</Context>go deeper
Know that Tomcat holds sessions in the JVM's memory, so anything that ends the process normally ends the sessions unless something was configured to save them.
Explain StandardManager's unload and load to SESSIONS.ser, the requirement that attributes be Serializable, and why a kill signal or a redeploy leaves nothing to restore.
Diagnose the specific case — restart versus redeploy versus a request landing elsewhere — read the serialization warnings, and weigh PersistentManager, replication and an external store against what the application actually needs.
Own the position that user state coupled to a process lifetime constrains every release and scaling decision, and decide when the organisation pays to make sessions external or the application stateless.
## What holds a session Each Tomcat Context has a `<Manager>`. Unless you configure one, Tomcat installs `StandardManager`: an in-memory map from session id to session, with a background thread expiring sessions past their `maxInactiveInterval` (set in `web.xml` under `<session-config>`). The id travels in the `JSESSIONID` cookie, scoped to the context path. Everything lives in this JVM's heap and nowhere else. ## The persistence it does offer `StandardManager` implements *unload/load*. When the context is stopped cleanly it serializes active sessions to: ``` $CATALINA_BASE/work/<engine>/<host>/<appname>/SESSIONS.ser ``` and when the context starts it reads that file back and deletes it. So a planned `shutdown.sh`/`startup.sh` cycle can preserve logins. This is convenience, not durability, and the failure modes are what interviewers are after: - **No graceful stop, no file.** `kill -9`, a container OOM kill, a power loss, or a JVM crash all skip `unload()` entirely. So does a shutdown that times out while the connector is still draining. - **Non-serializable attributes.** Serialization requires every attribute value to be `Serializable` (Tomcat handles a few container-managed types specially). One attribute holding a database connection, an open stream, a Spring bean proxy or a lambda makes the session unrestorable; Tomcat logs a warning and drops it. - **Redeploy, not restart.** Redeploying the WAR clears the context's work directory and builds a brand-new class loader. Even where a file survived, the classes that would deserialize it are different classes, so restoration cannot be relied on. Sessions surviving a *server restart* and surviving a *redeploy* are different problems. - **Deliberately disabled.** `<Manager pathname=""/>` in the context descriptor switches persistence off — common in production because writing a heap of session objects to disk at shutdown can be slow, and because deserializing attacker-influenced session state is an attack surface. ```xml <Context> <Manager pathname=""/> </Context> ``` ## The alternatives, in ascending cost **`PersistentManager` with a store.** Swaps sessions out to a `FileStore` or `JDBCStore` continuously rather than only at shutdown, driven by `maxIdleSwap`, `minIdleSwap` and `maxIdleBackup`. It also caps heap usage for very large session populations. Cost: serialization on the request path, and every attribute must still be serializable. **Clustering.** `<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">` with `DeltaManager` (replicate to all nodes) or `BackupManager` (one backup per session) keeps sessions alive across node loss, and requires `<distributable/>` in `web.xml`. Cost: multicast or explicit membership, replication traffic proportional to session churn, and a hard requirement that everything in the session serializes cheaply. It scales badly past a handful of nodes with `DeltaManager`. **Externalise the session.** Keep the session in a shared store outside the JVM, or make the application stateless and carry state in a signed token. Then a restart, a redeploy, and a node dying are all the same non-event, and rolling deploys stop being a user-visible action. This is where most modern designs land, and the reason is that every in-container option couples user state to a process's lifetime. ## Diagnosing the reported symptom Separate the cases before choosing a fix. Ask whether users lose sessions on a *restart* (persistence path) or on a *redeploy* (expect loss by design). Check whether the JVM is being stopped gracefully at all — a supervisor sending `SIGKILL` after a short timeout is a frequent hidden cause. Look for `SESSIONS.ser` appearing at shutdown and disappearing at start-up; its absence proves `unload()` never ran or persistence is disabled. Read the logs for serialization warnings naming a specific attribute class. And check whether the session was ever on this node: behind multiple servers, a request landing on a different node than the one that created the session looks exactly like a session loss even though nothing was lost. ## Design note Whichever mechanism you pick, keep sessions small and serializable — a handful of identifiers, not object graphs. That single discipline is what makes persistence, swapping, replication and eventual externalisation all cheap, and its absence is why teams discover at the worst moment that their sessions cannot leave the heap.
- Why is losing sessions on a redeploy expected even when shutdown persistence works?Because a redeploy clears the context's work directory and creates a new class loader. The serialized attributes were written by classes from the old loader, and the file is gone in any case. Restart persistence and redeploy survival are separate problems; if sessions must survive releases, they have to live outside the application's class loader — an external store, replication, or a stateless token.
- What does a PersistentManager give you that StandardManager does not?Continuous swapping rather than a one-shot dump at shutdown. Sessions idle beyond `maxIdleSwap` are written to a `FileStore` or `JDBCStore` and evicted from the heap, so a large session population no longer sizes the heap, and a crash loses less. The price is serialization work on the request path when a swapped session is touched again, and the same hard requirement that attributes be serializable.
- Users report random logouts with no restarts at all. What would you check first?Whether requests are reaching more than one Tomcat. A session created on one node is invisible to another unless replication or a shared store is in place, and losing affinity looks identical to a session expiring. After that, check `maxInactiveInterval` against real user idle time, and whether the JSESSIONID cookie's path or attributes cause the browser to stop sending it on some URLs.
saying these in an interview costs you the question
- Assuming sessions always survive a Tomcat restart
- Storing non-serializable objects in the session
- Expecting a redeploy to preserve sessions
- Treating SESSIONS.ser as durable storage
- Confusing a lost session with a request hitting another node