MOSS timer jobs e il timer service
Data: 6/20/2007
Categoria: Sharepoint
Codice d'esempio


Nello sviluppo di soluzioni personalizzate basate su Windows Sharepoint Services, mi è capitato molto spesso di dover creare delle console application (degli eseguibili per intenderci) per l'esecuzione di operazioni sistematiche secondo certi intervalli di tempo. Prima dell’avvento di Office Sharepoint Server 2007, la creazione di un eseguibile era l'unico modo per effettuare delle operazioni schedulate.
Ora invece, Microsoft ha pensato bene di introdurre i "timer jobs", delle particolari classi di oggetti le cui istanze vengono eseguite da un processo di Sharepoint, nei tempi stabiliti alla loro installazione. Il servizio che si occupa di eseguire questi task, è nominato "Windows Sharepoint Timer Service" (SPTimerV3).
L'intero sistema stesso di Sharepoint, utilizza questi oggetti per i suoi scopi:
  • Database delle statistiche e dei report
  • Meccanismo degli alert
  • Cleanup di siti
  • Sincronizzazione dei profili
  • Cestino
  • e tanti altri ...
La lista dei job presenti è visualizzabile dalla Central Administration, seguendo il percorso Operations > Timer Jobs Definitions; in questa pagina è possibile vedere i nomi dei vari job, la Web Application in cui sono registrati e il tipo di schedulazione. Andando invece nella pagina "Timer Job Status", è possibile abilitare o disabilitare specifici job, vederne la percentuale di esecuzione, l'ultimo risultato disponibile (per controllare che non siano terminati con degli errori), il server su cui girano e la data di ultima esecuzione.

Timer Jobs Definitions

Figura 1 - Timer Jobs Definitions
Timer Job Status

Figura 2 - Timer Job Status

Chiaramente, come tutte le nuove funzionalità inserite in questa nuova versione del prodotto, anche il sistema dei timer job può essere esteso, attraverso la creazione di propri job.
Come fare ? Niente di più facile, basta creare la solita libreria di classi .NET, segnarla tramite una chiave ed aggiungere una nuova classe che erediti dalla classe SPJobDefinition (presente nel namespace Microsoft.SharePoint.Administration). Tale classe obbliga la definizione di tre costruttori, e di un metodo, il metodo Execute, che conterrà il codice .NET che vogliamo far eseguire agli intervalli di tempo prestabiliti.
Nell'esempio che ho deciso di proporvi, ho creato un timer job per controllare quando un workflow (nello specifico un'approval workflow) è giunto al termine. Questa è risultata una necessità vera e propria, in quanto non è presente alcun evento che ci permette di stabilire quando il workflow è completato o meno (neanche l'evento ItemUpdated di una lista, in quanto non viene scatenato).

using System;

using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;

namespace Peppe.Sharepoint.Jobs
{
public class WorkflowMonitor : SPJobDefinition
{
public WorkflowMonitor() : base() { }

public WorkflowMonitor(string jobName, SPService service,
SPServer server, SPJobLockType targetType)
: base(jobName, service, server, targetType) { }

public WorkflowMonitor(string jobName, SPWebApplication webApplication)
: base(jobName, webApplication, null, SPJobLockType.ContentDatabase)
{
this.Title = "Approval Workflow Monitor";
}

public override void Execute(Guid targetInstanceId)
{
SPSite site = new SPSite("http://localhost");
using (site)
{
SPWeb web = site.OpenWeb();
using (web)
{
SPList list = web.Lists["NomeLista"];
SPListItemCollection items = list.Items;

foreach (SPListItem item in items)
{
if (item.Workflows[0].IsCompleted)
{
//WORKFLOW COMPLETATO ! }

if (item["NomeCampo"] != null)
{
if (item["NomeCampo"].ToString() == "16")
{
//ITEM APPROVATO }
if (item["NomeCampo"].ToString() == "17")
{
//ITEM RIFIUTATO }
}
}
}
}
}
}
}

Ora basta compilare, inserire la dll nella GAC del server Sharepoint ed effettuare un IISRESET.

Installazione del job

Una volta creata la nostra libreria contente il job d'esempio, dobbiamo preoccuparci dell'installazione.
Purtroppo, come per alcuni tipi di event handler, l'unico modo di registrare un job all'interno di Sharepoint è attraverso la scrittura di alcune righe di codice; queste possono essere inserite sia all'interno di un receiver di una feature (per questo si rimanda alla lettura dell’articolo sugli event handler), sia all'interno di una console application.

Per questo esempio ho scelto di sviluppare una console application. Dobbiamo aggiungerla alla soluzione corrente di Visual Studio .NET ed inserire tra le reference la libreria di classi contenente il nostro job.
Nel main dell'applicazione, dobbiamo quindi creare una nuova istanza del nostro job e una nuova istanza della classe SPMinuteSchedule, classe che ci permette di settare i valori temporali di esecuzione del nostro job, specificandoli in minuti, altrimenti è possibile utilizzare la classe SPDailySchedule, in modo tale da far girare il job ogni tot giorni.

Nota: ogni definizione di un singolo job, deve essere associata ad una Web Application Sharepoint; proprio per questo, dobbiamo creare un’istanza della nostra, utilizzando il costruttore che richiede come parametri il nome del job e la relativa web application.

Fatto questo, dobbiamo scrivere le righe necessarie per stoppare e far ripartire il Timer Service di Sharepoint (servizio SPTimerV3), in modo tale da metterlo a conoscenza della presenza del nostro job o di una sua nuova versione.

namespace InstallJob

{
class Program
{
const string NOMEJOB = "WorkflowMonitor";

static void Main(string[] args)
{
InstallJob();

Console.WriteLine("Job installato correttamente");
Console.Read();
}

private static void InstallJob()
{
SPSite site = new SPSite("http://localhost");
using (site)
{
//cancello la definizione del job foreach (SPJobDefinition j in site.WebApplication.JobDefinitions)
{
if (j.Name == NOMEJOB)
j.Delete();
}

//istanza del job WorkflowMonitor job = new WorkflowMonitor(NOMEJOB, site.WebApplication);
SPMinuteSchedule schedule = new SPMinuteSchedule();
schedule.BeginSecond = 0;
schedule.EndSecond = 59;
schedule.Interval = 1;
job.Schedule = schedule;
job.Update();

//servizio "Windows Sharepoint Services Timer" ServiceController controller = new ServiceController();
controller.MachineName = ".";
controller.ServiceName = "SPTimerV3";

//stop del servizio controller.Stop();
//attendo la fine dello stop Thread.Sleep(3000);
//start del servizio controller.Start();
}
}
}
}

Conclusioni

L'introduzione dei timer job è un'altra delle novità più belle inserite nella nuova versione di Sharepoint. Attraverso questa funzionalità infatti, è possibile evitare l'utilizzo di eseguibili schedulati sul server per compiere le nostre operazioni personalizzate. Inoltre, possiamo far girare del codice .NET con le credenziali del servizio che ospita il job e personalizzare il comportamento di tutti gli oggetti presenti in un’intera Web Application.

Link utili
Creating Custom SharePoint Timer Jobs di Andrew Connell (Sharepoint MVP)
SPJobDefinition class
SPMinuteSchedule class
SPDailySchedule class