2012-05-30 15 views
7

Bien, un poco de fondo aquí. Tengo una aplicación web a gran escala (MVC3) que hace todo tipo de cosas sin importancia. Necesito que esta aplicación web tenga la capacidad de programar trabajos Quartz.NET ad-hoc en una base de datos Oracle. Luego, deseo que los trabajos se ejecuten más tarde a través de un servicio de ventanas . Idealmente, me gustaría programar que se ejecuten en intervalos regulares, pero con la opción de agregar trabajos a través de la aplicación web.Tricky Quartz.NET Escenario

Básicamente, la arquitectura deseada es alguna variación de esto:

aplicación Web < -> Quartz.NET < -> Base de datos < -> Quartz.NET < -> servicio de Windows

Lo que he codificado hasta ahora:

  • Un servicio de Windows que (por el momento) programa Y ejecuta los trabajos. Obviamente, este no será el caso a largo plazo, pero me pregunto si puedo mantener esto y modificarlo para que básicamente represente a ambos "Quartz.NET" en el diagrama anterior.
  • La aplicación web (supongo detalles no son muy importantes aquí)
  • Los puestos de trabajo (que en realidad son simplemente otro servicio ventanas)

Y un par de notas importantes:

  • TIENE que ejecutarse desde un servicio de Windows, y TIENE que programarse a través de la aplicación web (para reducir la carga en IIS)
  • La arquitectura de arriba se puede reordenar un poco, suponiendo que el ab ove bala todavía se aplica.

Ahora, algunas preguntas:

  1. Es esto posible?
  2. Asumiendo (1) pasa, ¿qué piensan ustedes que es la mejor arquitectura para esto? Vea la primera viñeta en lo que he codificado.
  3. ¿Puede alguien darme algunos métodos de Quartz que me ayuden a consultar el DB para que los trabajos se ejecuten una vez que ya están programados?

Habrá una recompensa en esta pregunta tan pronto como sea elegible. Si la pregunta es respondida de manera satisfactoria antes de esa fecha, aún otorgaré la recompensa al cartel de la respuesta. Entonces, en cualquier caso, si das una buena respuesta aquí, obtendrás una recompensa.

+0

Bien, algunas preguntas primero. ¿Qué es, según usted, un trabajo de Quartz? Hice una investigación rápida sobre esto y parece que un trabajo Quartz.Net es una implementación auto escrita de una interfaz. El proyecto de Quartz es la parte que hace la programación. Los trabajos se pueden almacenar en una base de datos Oracle con el uso de ADO.net de acuerdo con la página principal del proyecto. ¿Cuál es tu problema real aquí? – Remco

+0

Bueno, estoy tratando de descubrir cómo dividir las cosas de Quartz para que una entidad las planifique y otra entidad las ejecute. Normalmente, simplemente hago algo como: _scheduler.ScheduleJob (jobDetail, trigger); Pero eso lo configura para disparar automáticamente de vez en cuando, dependiendo de 'trigger'. Me gustaría mantener esa funcionalidad, pero también obtener la funcionalidad para programar trabajos sobre la marcha –

+0

Y el trabajo de cuarzo en mi caso es un servicio de Windows que purga archivos innecesarios del sistema –

Respuesta

25

Trataré de responder a sus preguntas en el orden en que las tiene.

  1. Sí, es posible hacerlo. En realidad, es una forma común de trabajar con Quartz.Net. De hecho, también puede escribir una aplicación ASP.Net MVC que administre los programadores de Quartz.Net.

  2. Arquitectura. De manera ideal y en un nivel alto, su aplicación MVC utilizará la API Quartz.Net para hablar con un servidor Quartz.Net que se instala como un servicio de Windows en alguna parte. Cuarzo.Net usa la comunicación remota para comunicarse de forma remota, por lo que se aplican las limitaciones de uso de la comunicación remota (como no es compatible con Silverlight, etc.). Quartz.Net proporciona una manera de instalarlo como un servicio de Windows listo para usar, por lo que realmente no hay mucho trabajo por hacer aquí, aparte de configurar el propio servicio para usar (en su caso) una AdoJobStore, y también habilitar Remoting. Se debe tener cuidado con la forma de instalar el servicio correctamente, de modo que si aún no lo ha hecho, eche un vistazo a at this post.

Internamente, en su aplicación MVC querrá obtener una referencia al programador y almacenarlo como singleton. Luego, en su código, programará trabajos y obtendrá información sobre el programador a través de esta instancia única. Puede usar algo como esto:

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; 
    } 
} 

Este código configura su cliente Quart.Net. A continuación, para acceder al programador a distancia, a llamar a

GetScheduler() 
  1. Consulta Aquí algunos ejemplos de código para obtener todos los puestos de trabajo del planificador:

    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; 
    } 
    

Puede ver el código de en Github

+0

¡Esa es una buena respuesta! Ayudó inmensamente. Haber hecho +1, aceptado y recompensa por venir. –

+0

oh- creo que tengo que quitar tu estado de aceptación por un tiempo antes de que pueda poner la recompensa aquí –