Perdita continua delle sessioni in una Web Application: come indagare.
La causa più frequente di perdita delle sessioni è il crash del processo w3wp o il restart dell’AppDomain che processa l’applicazione.
Quando si nota che l’applicazione perde le sessioni la prima cosa da fare è abilitare i WebEvent:
ASP.NET Health Monitoring
http://msdn.microsoft.com/en-us/library/ms178701(VS.80).aspx
Si apra il Web.Config e, all’interno del tag <System.Web> si aggiunga quanto segue:
<healthMonitoring enabled="true" heartbeatInterval="0">
<rules>
<add name="Lifetime event logging rule" eventName="Application Lifetime Events" provider="EventLogProvider" />
</rules>
</healthMonitoring>
A questo punto, in caso di restart dell’Applicazione, tipicamente vengono registrati i seguenti messaggi nell’EventLog:
Event Type: Information
Event Source: ASP.NET 2.0.50727.0
Event Category: Web Event
Event ID: 1305
Date:
Time: 3:00:11 PM
User:
Computer:
Description:
Event code: 1001
Event message: Application is starting.
Event time:
Event time (UTC):
Event ID: e842cd86c62940788ed106f0f58ae8e4
Event sequence: 1
Event occurrence: 1
Event detail code: 0
Application information:
Application domain:
Trust level: Full
Application Virtual Path:
Application Path:
Machine name:
Process information:
Process ID: 1600
Process name: w3wp.exe
Account name:
Event Type: Information
Event Source: ASP.NET 2.0.50727.0
Event Category: Web Event
Event ID: 1305
Date:
Time: 3:00:11 PM
User:
Computer:
Description:
Event code: 1002
Event message: Application is shutting down.
Event time:
Event time
Event ID: b1294ac7629241b8b385cc1312b31dae
Event sequence: 2361
Event occurrence: 1
Event detail code: 50001
Per saperne di più è possibile prendere dei dump in crash mode.
Ecco come procedere all’analisi.
1) Carico l’estensione sos
2) Trovo tutte le istanze di HttpRuntime presenti nella heap
0:000> .loadby sos.dll mscorwks
0:000> !dumpheap -type System.Web.HttpRuntime
------------------------------
Heap 3
Address MT Size
07892270 6639a67c 152
0789d268 6639a67c 152
total 2 objects
3) Dumpo l’istanza per vederne i campi:
0:000> !do 0789d268
Name: System.Web.HttpRuntime
MethodTable: 6639a67c
EEClass: 6639a60c
Size: 152(0x98) bytes
(C:\WINDOWS\assembly\GAC_32\System.Web\2.0.0.0__b03f5f7f11d50a3a\System.Web.dll)
Fields:
MT Field Offset Type VT Attr Value Name
791132b4 40010f8 4 ...amedPermissionSet 0 instance 00000000 _namedPermissionSet
6639b12c 40010f9 8 ...ileChangesMonitor 0 instance 0789d75c _fcm
6639e2c8 40010fa c ...ing.CacheInternal 0 instance 0789f540 _cacheInternal
6639d878 40010fb 10 ...Web.Caching.Cache 0 instance 0789f458 _cachePublic
7910be50 40010fc 74 System.Boolean 1 instance 0 _isOnUNCShare
6639ad78 40010fd 14 ...Web.Util.Profiler 0 instance 0789d300 _profiler
6639ae78 40010fe 18 ...estTimeoutManager 0 instance 0789d31c _timeoutManager
663aebe4 40010ff 1c ....Web.RequestQueue 0 instance 078fe1a4 _requestQueue
7910be50 4001100 75 System.Boolean 1 instance 0 _apartmentThreading
7910be50 4001101 76 System.Boolean 1 instance 1 _processRequestInApplicationTrust
7910be50 4001102 77 System.Boolean 1 instance 0 _beforeFirstRequest
7910c878 4001103 84 System.DateTime 1 instance 0789d2ec _firstRequestStartTime
7910be50 4001104 78 System.Boolean 1 instance 1 _firstRequestCompleted
7910be50 4001105 79 System.Boolean 1 instance 1 _userForcedShutdown
7910be50 4001106 7a System.Boolean 1 instance 1 _configInited
7910be50 4001107 7b System.Boolean 1 instance 1 _fusionInited
79102290 4001108 6c System.Int32 1 instance 0 _activeRequestCount
7910c878 4001109 8c System.DateTime 1 instance 0789d2f4 _lastShutdownAttemptTime
7910be50 400110a 7c System.Boolean 1 instance 1 _shutdownInProgress
790fd8c4 400110b 20 System.String 0 instance 100171a4 _shutDownStack
790fd8c4 400110c 24 System.String 0 instance 07f25c80 _shutDownMessage
663e8730 400110d 70 System.Int32 1 instance 1 _shutdownReason
790fd8c4 400110e 28 System.String 0 instance 078c4f00 _trustLevel
790fd8c4 400110f 2c System.String 0 instance 0789d508 _wpUserId
7910be50 4001110 7d System.Boolean 1 instance 1 _shutdownWebEventRaised
7910be50 4001111 7e System.Boolean 1 instance 1 _enableHeaderChecking
7910d7e8 4001112 30 System.AsyncCallback 0 instance 0789d53c _requestNotificationCompletionCallback
7910d7e8 4001113 34 System.AsyncCallback 0 instance 0789d55c _handlerCompletionCallback
6639b038 4001114 38 ...fSendNotification 0 instance 0789d57c _asyncEndOfSendCallback
791186fc 4001115 3c ...ding.WaitCallback 0 instance 0789d59c _appDomainUnloadallback
790fdf04 4001116 40 System.Exception 0 instance 00000000 _initializationError
7910be50 4001117 7f System.Boolean 1 instance 0 _hostingInitFailed
791127fc 4001118 44 ...m.Threading.Timer 0 instance 00000000 _appDomainShutdownTimer
790fd8c4 4001119 48 System.String 0 instance 078d5cd0 _tempDir
790fd8c4 400111a 4c System.String 0 instance 078d5ee8 _codegenDir
790fd8c4 400111b 50 System.String 0 instance 07891820 _appDomainAppId
790fd8c4 400111c 54 System.String 0 instance 07891864 _appDomainAppPath
6639b220 400111d 58 ...m.Web.VirtualPath 0 instance 0789d734 _appDomainAppVPath
790fd8c4 400111e 5c System.String 0 instance 0789321c _appDomainId
7910be50 400111f 80 System.Boolean 1 instance 0 _debuggingEnabled
7912dae8 4001120 60 System.Byte[] 0 instance 00000000 _appOfflineMessage
790fd8c4 4001121 64 System.String 0 instance 00000000 _clientScriptVirtualPath
790fd8c4 4001122 68 System.String 0 instance 00000000 _clientScriptPhysicalPath
Si può subito vedere che il campo _shutdownInProgress è valorizzato a 1, il che significa che l’AppDomain sta per essere scaricato dalla memoria.
4) Possiamo dumpare lo _shudownStack e lo _shutdownMessage per avere maggiori dettagli:
0:000> !do 100171a4
Name: System.String
MethodTable: 790fd8c4
EEClass: 790fd824
Size: 1038(0x40e) bytes
GC Generation: 1
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at System.Web.Hosting.HostingEnvironment.InitiateShutdownInternal()
at System.Web.Hosting.HostingEnvironment.UnregisterRunningObjectInternal(IRegisteredObject obj)
at System.Web.Hosting.HostingEnvironment.UnregisterObject(IRegisteredObject obj)
at System.Web.Hosting.ISAPIRuntime.StopProcessing()
0:000> !do 07f25c80
Name: System.String
MethodTable: 790fd8c4
EEClass: 790fd824
Size: 164(0xa4) bytes
GC Generation: 1
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: Overwhelming Change Notification
HostingEnvironment caused shutdown
Risulta ora chiaro il motivo per cui l’applicazione viene riavviata. Qualcuno o qualcosa sta scrivendo, modificando o cancellando i file dell’applicazione o il virtual path all’interno del quale l’applicazione è contenuta
Ecco infatti alcune delle possibili cause di AppDomain restart:
Application Restarts
Modifying the source code of your Web application will cause ASP.NET to recompile source files into assemblies. When you modify the top-level items in your application, all other assemblies in the application that reference the top-level assemblies are recompiled as well.
In addition, modifying, adding, or deleting certain types of files within the application's known folders will cause the application to restart. The following actions will cause an application restart:
Adding, modifying, or deleting assemblies from the application's Bin folder.
Adding, modifying, or deleting localization resources from the App_GlobalResources or App_LocalResources folders.
Adding, modifying, or deleting the application's Global.asax file.
Adding, modifying, or deleting source code files in the App_Code directory.
Adding, modifying, or deleting Profile configuration.
Adding, modifying, or deleting Web service references in the App_WebReferences directory.
Adding, modifying, or deleting the application's Web.config file.
When an application restart is required, ASP.NET will serve all pending requests from the existing application domain and the old assemblies before restarting the application domain and loading the new assemblies.
Estratto da ASP.NET Application Life Cycle Overview for IIS 5.0 and 6.0
A partire dal Framework 2.0 se n’è inoltre aggiunto un altro:
- Application Sub-Directories are deleted
Quest’ultimo punto è discusso in dettaglio nel seguente post:
Todd Carter's WebLog : Deleting ASP.NET 2.0 Application Sub-Directories Shuts Down the AppDomain
Per monitorare il Virtual Path e vedere se qualcuno vi scrive dentro o ne modifica l’albero una possibilità è quella di usare il Process Monitor.
Una volta individuata la causa e scoperto chi e cosa compie le operazioni incriminate, è possibile agire in due modi:
- il primo, consigliato, è quello di rimuovere la causa facendo si che il Virtual Path non venga toccato
- il secondo, molto più delicato e da valutare con attenzione, è quello di disabilitare parzialmente o totalmente la File Change Notification come spiega questo articolo (che però discute un altro problema:
FIX: ASP.NET 2.0-connected applications on a Web site may appear to stop responding
Nella fattispecie di questo caso, era l’applicazione stessa a creare e cancellare cartelle e file al di sotto della root applicativa. Si è optato per la seconda soluzione perché, per motivi di policy interne, non era possibile spostare il working path al di fuori della root.
Alla prossima
Stefano Pronti
Senior Support Engineer
EMEA IIS and Web Developer Support Team