2010-11-24 71 views
5

Estoy intentando implementar Quartz.NET como un servicio de Windows en C#. Mis trabajos no se disparan cuando espero que se disparen ... en absoluto, en realidad, por lo que puedo ver.Quartz.NET - ¿Los trabajos no se ejecutan?

Tengo mi programa de trabajo ejecutándose a partir del minuto siguiente incluso después de la ejecución "minuciosamente". Sin embargo, cuando llega el próximo minuto, parece que no puedo decir si realmente funciona algo.

Supongo que cuando se ejecuta mi trabajo, una ventana CLI aparecería en la ejecución del trabajo, y las operaciones de la Consola serían visibles, (incluso puse un Console.ReadKey() para asegurar que la ventana no se abre y cierra tan rápido No puedo verlo), pero hasta donde sé, el cronograma simplemente no está ejecutando trabajos.

Me di cuenta de que todos los tiempos están en UTC, y que el StartTimeUtc se configurará a la hora UTC que es +6 horas desde la hora de mi computadora local, pero también asumiría que el planificador de Quartz maneja eso calculando la ejecución desde mi configuración de TimeZone, aunque no tengo manera de saberlo para confirmarlo, ni para confirmar los tiempos ACTUALES en los que está configurado mi horario.

Imagino que hay alguna forma de configurar el ensamblado de Registro común y utilizarlo para ayudarme a saber cuál es mi estado, pero aún tengo que averiguar qué hacer con eso para habilitar un registro de cualquier tipo para obtener retroalimentación de mi Servicio de Windows, además de escribir en el registro de eventos que creé para él.

Mi función OnStart de mi servicio de Windows

protected override void OnStart(string[] args) 
    { 
     eventLog.WriteEntry("--- STARTING eLoyalty Scheduler Service ---"); 

     // construct a scheduler factory 
     ISchedulerFactory schedFact = new StdSchedulerFactory(); 

     // get a scheduler 
     IScheduler sched = schedFact.GetScheduler(); 

     // construct job info 
     JobDetail jobDetail = new JobDetail("eLoyaltySchedulerService", null, typeof(PortalSchedulerJob)); 
     jobDetail.JobDataMap["jobSays"] = "eLoyalty Scheduler Service Executing!"; 
     jobDetail.JobDataMap["myStateData"] = new ArrayList(); 

     // fire every minute 
     Trigger trigger = TriggerUtils.MakeMinutelyTrigger(); 

     // start on the next even minute 
     trigger.StartTimeUtc = TriggerUtils.GetEvenMinuteDate(DateTime.UtcNow); 

     // name it 
     trigger.Name = "NextEvenMinute"; 

     // schedule it 
     sched.ScheduleJob(jobDetail, trigger); 

     // start the schedule 
     sched.Start(); 

     eventLog.WriteEntry("--- STARTED eLoyalty Scheduler Service ---"); 
    } 

de mi trabajo Ejecutar() función es la siguiente:

public void Execute(JobExecutionContext context) 
    { 
     try 
     { 
      string instName = context.JobDetail.Name; 
      string instGroup = context.JobDetail.Group; 
      JobDataMap dataMap = context.MergedJobDataMap; 
      string jobSays = dataMap.GetString("jobSays"); 
      ArrayList state = (ArrayList)dataMap["myStateData"]; 
      state.Add(DateTime.UtcNow); 

      Console.WriteLine("Instance {0} of PortalSchedulerJob says: {1} @ {2}", instName, jobSays, DateTime.UtcNow); 
      Console.ReadKey(); 
     } 
     catch (JobExecutionException Ex) 
     { 
      throw Ex; 
     } 
    } 

Si usted puede ayudar a averiguar cómo solucionar mi actividad de planificación real, Puedo ser capaz de resolver esto por mi cuenta ...?

Respuesta

0

Gracias por la entrada de todo el mundo .. . No pude conseguir nada de esto para trabajar, desafortunadamente, pero cuando agregué un n registrador de eventos en mi función de ejecución de trabajos, encontré que escribía en el registro de eventos cada minuto en el minuto como se esperaba.

Supongo que los funcionamientos Console.WriteLine() y Console.ReadKey() no hacen nada en un entorno de servicio de Windows?

NOTA: Hacen algo, pero en el fondo se ejecuta como un servicio en lugar de en una ventana de la consola ...

+1

Si mal no recuerdo, Console.Anything explota un servicio de Windows. –

0

Tuvimos algunos problemas con los disparadores que fallaron. I added a global trigger listener para detectar eventos relacionados con el despido de trabajos y que proporcionó la información necesaria para solucionar el problema.

También conectamos NLog a través de Common.Logging para capturar el registro interno de Quartz (puede notar que usamos Simple Logging Facade nosotros mismos, por lo que el componente también se configura aquí). Aquí está nuestra aplicación de configuración, es de esperar que puede saltar empezar:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <configSections> 
     <section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" /> 
     <section name="slf" type="Slf.Config.SlfConfigurationSection, slf"/> 
     <sectionGroup name="common"> 
      <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" /> 
     </sectionGroup> 
    </configSections> 


    <quartz> 
     <add key="quartz.threadPool.threadCount" value="20" /> 
     <add key="quartz.jobStore.misfireThreshold" value="420000" /><!-- 7 minutes --> 
    </quartz> 


    <slf> 
     <factories> 
      <factory name="nlog" type="SLF.NLogFacade.NLogLoggerFactory, SLF.NLogFacade"/> 
     </factories> 

     <loggers> 
      <logger factory="nlog"/> 
     </loggers> 
    </slf> 

    <common> 
     <logging> 
      <factoryAdapter type="Common.Logging.NLog.NLogLoggerFactoryAdapter, Common.Logging.NLog"> 
       <arg key="configType" value="FILE" /> 
       <arg key="configFile" value="~/NLog.config" /> 
      </factoryAdapter> 
     </logging> 
    </common> 

</configuration> 
8

En Quartz.NET tareas, sólo debe lanzar excepciones JobExecutionException: Quartz.net- Lesson 3:

El (..) Método Job.Execute Finalmente, nosotros necesitamos informarle de algunos detalles de el método IJob.Execute (..). El único tipo de excepción que se le permite arrojar desde el método de ejecución es JobExecutionException. Debido a esto, generalmente debe envolver el contenido completo del método de ejecución con un bloque 'try-catch'. Usted debe también pasar algún tiempo buscando en la documentación para el JobExecutionException, ya que su trabajo puede utilizarlo para proporcionar el planificador diversas directivas en cuanto a cómo desea la excepción a manipular.

En lugar de:

catch (JobExecutionException Ex) 
{ 
    throw Ex; 
} 

hacer algo como esto:

catch (Exception err) 
{ 
    // Only allow JobExecutionException exceptions to be thrown... 
    throw new Quartz.JobExecutionException(err); 
} 

A continuación, puede controlar la excepción centralizada:

_globalJobListener = new GlobalJobListener(); 
sched.AddGlobalJobListener(_globalJobListener); 


public class GlobalJobListener : Quartz.IJobListener 
{ 
    public GlobalJobListener() 
    { 
    } 

    public virtual string Name 
    { 
     get { return "MainJobListener"; } 
    } 

    public virtual void JobToBeExecuted(JobExecutionContext context) 
    {  
    } 

    public virtual void JobWasExecuted(JobExecutionContext inContext, JobExecutionException inException) 
    { 
     if (inException != null) 
     { 
      // Log/handle error here 
     } 
    } 


    public virtual void JobExecutionVetoed(JobExecutionContext inContext) 
    { 

    } 
} 
+0

Esto es útil, pero no una respuesta a esta pregunta en particular! :) – Rimer

+0

Muy cierto. Estoy tan absorto en el manejo de excepciones que ni siquiera noté tu uso de la consola, ¡lo que ciertamente no funciona en un servicio de Windows! –

+0

@keith - Los servicios de Windows pueden enviar a la consola. Debe habilitar el acceso interactivo para esto. – Matt

2

Siempre se puede ejecutar el servicio de Windows en la consola cuando se va a depurar:

static class Program 
{ 
    static void Main() 
    { 
     var servicesToRun = new ServiceBase[] 
      { 
       new CassetteDeckService() 
      }; 

     if (Environment.UserInteractive) 
     { 
      var type = typeof(ServiceBase); 
      const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic; 
      var method = type.GetMethod("OnStart", flags); 

      foreach (var service in servicesToRun) 
      { 
       method.Invoke(service, new object[] { null }); 
      } 

      Console.WriteLine("Service Started!"); 
      Console.ReadLine(); 

      method = type.GetMethod("OnStop", flags); 

      foreach (var service in servicesToRun) 
      { 
       method.Invoke(service, null); 
      } 
      Environment.Exit(0); 
     } 
     else 
     { 
      ServiceBase.Run(servicesToRun); 
     } 
    } 
} 

Simplemente asegúrese de cambiar el tipo de aplicación a la Aplicación de consola en las propiedades de su proyecto de servicio de Windows (esto no afectará su ejecución como un servicio de Windows cuando no se ejecuta en modo interactivo).

+0

¡Buen truco para poder cambiar a la consola durante la depuración! – Mrchief

0

si desea depurar su trabajo mantener el estudio visual abierta, en su código de puesto de venta:

System.Diagnostics.Debugger.Launch();

que le permitirá conectarse al depurador en Visual Studio y podrá ver lo que está sucediendo.

Como alternativa, si desea que el registro común funcione, envíeme un mensaje ya que todo funciona bien en mi servicio de Windows.

Cuestiones relacionadas