2012-05-30 15 views
7

Ok, po 'di fondo qui. Ho un'applicazione web su larga scala (MVC3) che fa tutti i tipi di cose non importanti. Ho bisogno di questa applicazione web per avere la possibilità di pianificare lavori Quartz.NET ad-hoc in un database Oracle. Quindi, desidero che i lavori vengano eseguiti in un secondo momento tramite un servizio Windows . Idealmente, mi piacerebbe programmarli per funzionare a intervalli regolari, ma con la possibilità di aggiungere posti di lavoro tramite l'app web.Tricky Quartz.NET Scenario

In sostanza, l'architettura desiderata è qualche variazione di questo:

Web App < -> Quartz.NET < -> Database < -> Quartz.NET < -> Windows Service

Quello che ho codificato finora:

  • Un servizio di Windows che (per ora) pianifica AND esegue i lavori. Questo ovviamente non sarà il caso a lungo termine, ma mi chiedo se posso mantenere solo questo e modificarlo per farlo rappresentare sostanzialmente entrambi "Quartz.NET" nel diagramma sopra.
  • L'applicazione web (credo che non sono molto importanti qui)
  • I posti di lavoro (che sono in realtà solo un altro servizio finestre)

e un paio note importanti:

  • deve essere eseguito da un servizio di Windows, e deve essere programmato attraverso l'applicazione web (per ridurre il carico su IIS)
  • l'architettura sopra può essere riorganizzate un po ', assumendo l'ab ove si applica ancora il proiettile.

Ora, alcune domande:

  1. Questo è anche possibile?
  2. Supponendo (1) passa, che cosa ne pensate voi ragazzi è la migliore architettura per questo? Guarda il primo punto su ciò che ho codificato.
  3. Qualcuno può forse darmi alcuni metodi di quarzo che mi aiuterà con l'interrogazione del DB per i lavori da eseguire una volta che sono già programmati?

Ci sarà una taglia su questa domanda non appena è ammissibile. Se la domanda viene data una risposta soddisfacente prima di allora, assegnerò comunque il premio al poster della risposta. Quindi, in ogni caso, se dai una buona risposta qui, otterrai una taglia.

+0

Ok, alcune domande prima. Cosa è secondo te un lavoro al quarzo? Ho fatto alcune ricerche veloci su di esso e sembra che un Quartz.Net Job sia un'implementazione auto-scritta di un'interfaccia. Il progetto Quartz è la parte che fa la programmazione. I lavori possono essere archiviati in un database Oracle con l'uso di ADO.net in base alla pagina principale del progetto. Qual è il tuo vero problema qui? – Remco

+0

Beh, sto solo cercando di capire come suddividere il materiale Quartz in modo che una entità li programmi e un'altra entità li esegua. Normalmente, vorrei fare qualcosa come: _scheduler.ScheduleJob (jobDetail, trigger); Ma questo lo imposta per sparare automaticamente ogni tanto, a seconda del 'trigger'. Mi piacerebbe mantenere questa funzionalità, ma anche ottenere la funzionalità per pianificare i lavori al volo –

+0

E il lavoro al quarzo nel mio caso è un servizio Windows che elimina i file non necessari dal sistema –

risposta

25

cercherò rispondere alle vostre domande nell'ordine in cui li avete.

  1. Sì, è possibile farlo. In realtà è un modo comune di lavorare con Quartz.Net. Infatti, è anche possibile scrivere un'applicazione ASP.Net MVC che gestisce gli scheduler Quartz.Net.

  2. Architettura. Idealmente e ad un livello elevato, l'applicazione MVC utilizzerà l'API Quartz.Net per parlare con un server Quartz.Net installato come servizio Windows da qualche parte. Quarzo.Net utilizza la comunicazione remota per comunicare da remoto, quindi si applicano eventuali limitazioni dell'uso della comunicazione remota (come se non fosse supportato in Silverlight, ecc.). Quartz.Net fornisce un modo per installarlo come un servizio di Windows, quindi non c'è molto lavoro da fare qui, oltre alla configurazione del servizio stesso da utilizzare (nel tuo caso) un AdoJobStore, e anche abilitare la comunicazione remota. È necessario prestare attenzione a come installare correttamente il servizio, quindi se non lo hai ancora fatto, dai un'occhiata a at this post.

Internamente, nell'applicazione MVC si desidera ottenere un riferimento allo scheduler e memorizzarlo come un singleton. Quindi nel codice pianificherete i lavori e otterrete informazioni sullo scheduler attraverso questa istanza unica. Si potrebbe usare qualcosa di simile:

public class QuartzScheduler 
{ 
    public QuartzScheduler(string server, int port, string scheduler) 
    { 
     Address = string.Format("tcp://{0}:{1}/{2}", server, port, scheduler); 
     _schedulerFactory = new StdSchedulerFactory(getProperties(Address)); 

     try 
     { 
      _scheduler = _schedulerFactory.GetScheduler(); 
     } 
     catch (SchedulerException) 
     { 
      MessageBox.Show("Unable to connect to the specified server", "Connection Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); 
     } 
    } 
    public string Address { get; private set; } 
    private NameValueCollection getProperties(string address) 
    { 
     NameValueCollection properties = new NameValueCollection(); 
     properties["quartz.scheduler.instanceName"] = "RemoteClient"; 
     properties["quartz.scheduler.proxy"] = "true"; 
     properties["quartz.threadPool.threadCount"] = "0"; 
     properties["quartz.scheduler.proxy.address"] = address; 
     return properties; 
    } 
    public IScheduler GetScheduler() 
    { 
     return _scheduler; 
    } 
} 

Questo codice imposta il client Quart.Net. Poi per accedere al scheduler remota, basta chiamare

GetScheduler() 
  1. Interrogazione Ecco alcuni esempi di codice per ottenere tutti i posti di lavoro dal programmatore:

    public DataTable GetJobs() 
    { 
        DataTable table = new DataTable(); 
        table.Columns.Add("GroupName"); 
        table.Columns.Add("JobName"); 
        table.Columns.Add("JobDescription"); 
        table.Columns.Add("TriggerName"); 
        table.Columns.Add("TriggerGroupName"); 
        table.Columns.Add("TriggerType"); 
        table.Columns.Add("TriggerState"); 
        table.Columns.Add("NextFireTime"); 
        table.Columns.Add("PreviousFireTime"); 
        var jobGroups = GetScheduler().GetJobGroupNames(); 
        foreach (string group in jobGroups) 
        { 
         var groupMatcher = GroupMatcher<JobKey>.GroupContains(group); 
         var jobKeys = GetScheduler().GetJobKeys(groupMatcher); 
         foreach (var jobKey in jobKeys) 
         { 
          var detail = GetScheduler().GetJobDetail(jobKey); 
          var triggers = GetScheduler().GetTriggersOfJob(jobKey); 
          foreach (ITrigger trigger in triggers) 
          { 
           DataRow row = table.NewRow(); 
           row["GroupName"] = group; 
           row["JobName"] = jobKey.Name; 
           row["JobDescription"] = detail.Description; 
           row["TriggerName"] = trigger.Key.Name; 
           row["TriggerGroupName"] = trigger.Key.Group; 
           row["TriggerType"] = trigger.GetType().Name; 
           row["TriggerState"] = GetScheduler().GetTriggerState(trigger.Key); 
           DateTimeOffset? nextFireTime = trigger.GetNextFireTimeUtc(); 
           if (nextFireTime.HasValue) 
           { 
            row["NextFireTime"] = TimeZone.CurrentTimeZone.ToLocalTime(nextFireTime.Value.DateTime); 
           } 
    
           DateTimeOffset? previousFireTime = trigger.GetPreviousFireTimeUtc(); 
           if (previousFireTime.HasValue) 
           { 
            row["PreviousFireTime"] = TimeZone.CurrentTimeZone.ToLocalTime(previousFireTime.Value.DateTime); 
           } 
    
           table.Rows.Add(row); 
          } 
         } 
        } 
        return table; 
    } 
    

È possibile visualizzare il codice su Github

+0

Questa è una buona risposta! Ha aiutato immensamente. Hai fatto +1, accettato e taglie in arrivo. –

+0

oh- penso di dover togliere il tuo stato accettato per un po 'prima che possa mettere la taglia qui –