Users of an ASP.NET application hosted on IIS report being randomly signed out during the day, and the first request each morning takes about thirty seconds. How do IIS application pool recycling and the idle time-out explain both symptoms, and what would you change?
answer
- the process is not the same process
- 20 minutes quiet, then it dies
- 29 hours drifts around the clock
- overlapped recycle copies no state
- AlwaysRunning still needs preload
basics
~20 sBoth symptoms come from the worker process going away. The IIS application pool idle time-out kills w3wp.exe after 20 minutes with no requests, and periodic recycling restarts it roughly every 29 hours, discarding in-process session state and forcing a cold start on the next request.
solid answer
~50 sIIS shuts an application pool's worker process down when it has been idle for the configured period — 20 minutes by default — and also recycles it on a regular time interval, 1740 minutes by default, plus on private-memory or request-count limits. Every recycle throws away whatever the process held in memory, so in-process session state and caches vanish and users appear to be signed out at unpredictable moments; the next request pays the full cold start of loading the CLR, JIT-compiling and rebuilding those caches. The fixes are layered: move session state out of process so a recycle stops being user-visible, set the idle time-out to zero and `startMode` to `AlwaysRunning` with Application Initialization preloading the app, and replace the rolling 29-hour interval with a fixed off-peak schedule so recycles happen at 3 a.m. rather than at noon.
code
xml · 14 lines<applicationPools>
<add name="ContosoPool" startMode="AlwaysRunning" managedRuntimeVersion="v4.0">
<processModel identityType="ApplicationPoolIdentity"
idleTimeout="00:00:00" />
<recycling logEventOnRecycle="Time,Memory,ConfigChange"
disallowOverlappingRotation="false">
<periodicRestart time="00:00:00" memory="0" privateMemory="0">
<schedule>
<add value="03:00:00" />
</schedule>
</periodicRestart>
</recycling>
</add>
</applicationPools>go deeper
Know that IIS stops the worker process when a pool is idle and restarts it periodically, and that anything kept in memory — including in-process session — disappears when it does.
Quote the two defaults, 20 minutes idle and 1740 minutes periodic, and explain overlapped recycling, what preloadEnabled adds to AlwaysRunning, and why a fixed schedule beats a drifting interval.
Demonstrate that you separate the availability problem from the state problem: move state out of process first, then tune warm-up, and read the WAS events instead of assuming which trigger fired.
Frame it as a hosting-model decision — whether an application that cannot survive an arbitrary process restart belongs on shared IIS at all, and what deployment and state architecture you require before it does.
## Two different mechanisms, one shared consequence The symptoms look unrelated but have the same root: the `w3wp.exe` worker process serving the application pool is not the same process it was an hour ago. **Idle time-out** is a resource-reclamation feature. If no request arrives for the pool within `processModel/idleTimeout` — default `00:20:00` — the Windows Process Activation Service terminates the worker. On a machine hosting forty low-traffic intranet sites this is exactly what you want; on a single business application with quiet evenings it means every morning's first user pays for startup. **Recycling** is a hygiene feature inherited from an era of leaky native components. By default `recycling/periodicRestart` fires on a *time interval* of `1.05:00:00`, that is 29 hours or 1740 minutes, counted from when the worker started. Because 29 does not divide 24, the recycle time drifts around the clock — the reason an application can seem to "randomly" lose state in the middle of a workday. Recycles also fire on a private-memory limit, a virtual-memory limit, a request-count limit, on a configuration change, and on demand. Whatever the trigger, the effect is identical: the address space goes away. Anything held in `HttpContext.Session` with in-process mode, in `MemoryCache`, in a static field, in a connection pool or in a background timer is gone. ## Overlapped recycling is not state transfer By default a recycle is *overlapped* (`disallowOverlappingRotation="false"`): IIS starts the replacement worker, lets it initialise, moves new requests to it, and lets the old one drain its in-flight requests before exiting. That protects availability — clients do not see a gap — but it copies nothing. Session state does not migrate. It also means both processes exist briefly, so a pool near a memory limit can spike to roughly double its footprint at recycle time, and a second instance of any singleton background job runs for a few seconds. Disabling overlap is the right choice only when the application genuinely cannot tolerate two instances — an exclusive file lock, a scheduler with no leader election — and you accept the resulting gap. ## Fixing the sign-outs Recycling is not a bug to be switched off; it is a fact of the platform, and a pool can restart for reasons you do not control, such as a `web.config` edit. The durable fix is to stop keeping user-visible state in the process. Session state moved to an out-of-process store, and authentication cookies signed with keys held somewhere shared rather than regenerated per process, both survive a recycle untouched. Once that is true, a recycle is invisible and the remaining question is only about latency. Until then, you can reduce exposure by replacing the drifting interval with a fixed time: ```xml <recycling disallowOverlappingRotation="false"> <periodicRestart time="00:00:00"> <schedule><add value="03:00:00" /></schedule> </periodicRestart> </recycling> ``` Setting `time` to zero disables the interval; the `schedule` entries then recycle at named clock times. ## Fixing the cold start Three settings work together, and people usually apply only the first. 1. `processModel/idleTimeout="00:00:00"` stops IIS from shutting the worker down when traffic goes quiet. 2. `startMode="AlwaysRunning"` on the pool makes WAS start a worker as soon as the service starts, rather than waiting for the first request. Available from IIS 8.0. 3. `preloadEnabled="true"` on the application, with the Application Initialization role feature installed, makes IIS send a synthetic request into the newly started worker so initialisation happens before a real user arrives. Without this, `AlwaysRunning` gives you a process that has loaded almost nothing. From IIS 8.5, `idleTimeoutAction` can be set to `Suspend` instead of `Terminate`, which pages the idle worker out rather than killing it — a middle ground for dense shared hosting that keeps warm state at the cost of resident memory. What still remains after all of that is the recycle-time cold start, which `preloadEnabled` also covers because the replacement worker is initialised before requests move to it. ## Diagnosing it rather than guessing Do not argue from defaults. The System event log records WAS events for each recycle with the reason, and enabling `logEventOnRecycle` makes the reason explicit — time interval, memory, configuration change, on-demand. `appcmd list wp` before and after shows the process ID changing. And a startup that fails repeatedly is a different animal: rapid-fail protection disables the pool after five failures in five minutes and everything then answers 503, which is a stopped pool rather than a recycling one.
- Why does an edit to web.config produce the same symptom as a scheduled recycle?IIS watches the application's configuration and directory for changes and restarts the application on a change to `web.config`, the `bin` folder or `App_Data`. That drops in-process state exactly as a recycle does. It is why deploying during business hours signs everyone out on an application that keeps session in process, and another argument for moving session out.
- Users get an instant 503 and the pool shows as stopped rather than recycling. What is happening?Rapid-fail protection. If the pool's worker process fails more than the configured number of times — five by default — within the configured interval of five minutes, WAS stops the pool outright rather than restarting it forever. HTTP.sys then answers 503 with nothing reaching your code. Look in the System event log for the WAS event naming the failure, fix the startup fault, then start the pool.
- Is a private-memory recycle limit a reasonable safety net for a leaking application?As a stopgap only. It converts an eventual out-of-memory crash into a scheduled restart, which is better for availability, but it fires unpredictably, hits every application sharing the pool, and hides the leak from whoever should be fixing it. Set it with an alert attached so the recycle is visible, not silent.
saying these in an interview costs you the question
- Claims recycling transfers session state to the new process
- Thinks disabling recycling is the standard production fix
- Says AlwaysRunning alone removes the cold start
- Confuses idle time-out with the session time-out
- Assumes overlapped recycling means only one process exists