Technology Experience

Contenuti gestiti da Igor Damiani
posts - 949, comments - 2741, trackbacks - 15120

My Links

News

  • Questo blog si propone di raccogliere riflessioni, teoriche e pratiche, su tutto quello che riguarda il world-computing che mi sta attorno: programmazione in .NET, software attuale e futuro, notizie provenienti dal web, tecnologia in generale, open-source.

    L'idea è quella di lasciare una sorta di patrimonio personale, una raccolta di idee che un giorno potrebbe farmi sorridere, al pensiero di dov'ero e cosa stavo facendo.

    10/05/2005,
    Milano

Archives

Post Categories

Generale

Sono un servizio che dipende dall'Event Log, ricordatelo!

Durante alcuni giorni di luglio, avevo scritto un servizio managed (lo chiameremo AutoShutService) capace di monitorare l'attività del PC su cui è in esecuzione (soprattutto virtual machine) e, in base a certi criteri, di provocarne lo shutdown per evitare il consumarsi delle risorse messe a disposizione (principalmente memoria RAM). Il tutto è stato davvero un successo, perchè a quanto pare ho risolto una problematica che assillava da un po' di tempo i sistemisti della società dove lavoro, che ricercavano (inutilmente) su Internet un tool o un'utility che potesse aiutarli.

Al mio ritorno delle ferie estive, e quindi dopo circa 1 mese di attività sui server di produzione, è stato riscontrato un piccolo problema che ho voluto sistemare questa mattina. In pratica, l'installer che ho appositamente creato imposta il servizio in modo tale che parta in automatico. Questa impostazione non ha causato problemi nel 95% dei casi: in tutti i server (fisici e virtuali) che girano con Windows 2003, AutoShutService viene installato correttamente e parte ad ogni avvio senza alcuna controindicazione. Su qualcuno dei server (fisici e virtuali) che girano invece con Windows 2000 Server, invece, è capitato che l'avvio in automatico fallisse , mostrando sullo schermo un messaggio di errore:

The service did not respond to the start or control request in a timely fashion.

Sebbene il contenuto sia chiaro, ho googlato molto alla ricerca di una possibile soluzione. La prima cosa che ho pensato è che il mio servizio dipende da qualcun'altro, come in effetti è. Concettualmente parlando, AutoShutService sfrutta due risorse che posso essere critiche in questo scenario:

  1. EventLog: alla partenza, durante l'esecuzione e al termine, AutoShutService logga in un event log dedicato tutta una serie di informazioni più o meno interessanti.
  2. WMI: ad intervalli prestabiliti controllati da un System.Timers.Timer, utilizzo un PerformanceCounter per rilevare il "% Processor Time".

In ambedue i casi, ho a che fare con due servizi di Windows: il primo è Event Log, mentre il secondo è Windows Management Instrumentation. Se riporto qui sotto uno snippet di codice tratto dal costruttore dalla mia classe, salta subito all'occhio come effettivamente l'event log venga utilizzato fin da subito, e quindi potrebbe essere la fonte del mio problema:

public AutoShutService()
{
    InitializeComponent();

    settings = AutoShutSettings.Load();

    
if (settings.Log)
    {
        
if (!EventLog.SourceExists("AutoShutService Source"))
        {
            EventLog.CreateEventSource("AutoShutService Source", "AutoShutdown Log");
        }

        serviceLog.Source = "AutoShutService Source";
        serviceLog.Log = "AutoShutdown Log";
    }

    serviceLog.WriteEntry("AutoShutService starting...", EventLogEntryType.Information);
}

Se durante l'esecuzione del costruttore il servizio Event Log non è ancora partito, anche il mio AutoShutService ha qualche problema e fallisce il suo startup.

Risoluzione "da sistemisti"
Prima che mettessi mano al mio progetto Visual Studio 2005, i sistemisti hanno provato a sistemare la cosa autonomamente, ma con scarso successo!  Dopo il setup del mio servizio, sono andati nelle sue proprietà nell'elenco dei Services e, sotto il tab Recovery, hanno provato a settare la ComboBox relativa alla voci First failure, dicendo a Windows di far restartare il servizio stesso. Questo cambiamento non ha avuto alcun effetto, quindi sono dovuto rientrare in scena io.

AutoshutService: "Io dipendo da Event Log e da WMI, lo dici a Windows, per favore?"
Più che il codice del servizio in sè, ho dovuto toccare in realtà il suo installer, in modo tale da poter informare Windows delle dipendenze di cui ho bisogno. La classe Installer di .NET espone una proprietà ServicesDependedOn, che accoglie un'array di stringhe (string[]) che non è nient'altro che l'elenco dei nomi dei servizi da cui dipendo. Quindi, in breve:

[RunInstaller(true)]
public partial class ProjectInstaller : Installer
{
    
public ProjectInstaller()
    {
        InitializeComponent();

        
this.serviceInstaller1.ServicesDependedOn = 
            
new string[] { "Eventlog", "WinMgmt" };
    }
}

I nomi dei due servizi indicati sopra ("Eventlog" e "WinMgmt") non sono quelli in chiaro che leggiamo di solito, ma li ho reperiti nel registry all'interno della chiave HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services. Questa semplice modifica del mio installer ha fatto funzionare le cose: prima che AutoShutService venga fatto partire, Windows si assicura che prima siano partiti l'event log e WMI. Da tener presente che questa modifica è fattibile anche senza entrare nel codice: quando si eredita dalla classe Installer VS2005 offre un designer, nel quale vengono disposti un oggetto ServiceProcessInstaller ed un oggetto ServiceInstaller (entrambi contenuti nel namespace System.ServiceProcess ). Su quest'ultimo è possibile settare la proprietà ServicesDependedOn che prima abbiamo modificato in C#. Da qui possiamo dare anche una descrizione del servizio e settare per esempio la proprietà StartType su uno dei valori imposti dall'enum ServiceStartMode .

Qualche miglioria alla gestione dell'Event Log
Con .NET possiamo facilmente scrivere eventi nel nostro Event Log. Nel costruttore riportato sopra, si vede chiaramente che posso utilizzare la classe System.Diagnostics.EventLog per scrivere nuove entry:

serviceLog.WriteEntry("AutoShutService starting...",
    EventLogEntryType.Information);

La cosa interessante è che tramite l'istanza serviceLog possiamo modificare il comportamento standard dell'event log, per esempio settandone la dimensione massima (proprietà MaximumKilobytes), oppure il numero minimo di giorni da mantere nell'event log (proprietà MinimumRetentionDays) oppure - quello che serviva a me - decidere il comportamento dell'event log nel momento in cui raggiunge la sua dimensione massima (metodo ModifyOverflowPolicy). Questo metodo non fa altro che settare la proprietà (di sola-lettura) OverflowAction.

powered by IMHO 1.3

Print | posted on martedì 5 settembre 2006 17:45 | Filed Under [ Sviluppo .NET ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET