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