2011-11-23 13 views
5

Estoy usando Quartz con Spring para ejecutar una tarea específica a la medianoche del primer día del mes. He probado el trabajo estableciendo la fecha de mi servidor & para que sea 11:59 en el último día del mes, inicie el servidor y observe la ejecución de la tarea cuando se convierte en 12:00, pero me preocupan los casos en que servidor (por el motivo que sea) no se puede ejecutar a la medianoche del primer día del mes.Ejecutando un trabajo de cuarzo perdido

Supuse que el manejo de fallo de encendido en Quartz se encargaría de esto, pero tal vez estoy equivocado en eso?

¿Alguien me puede aconsejar sobre cómo podría manejar esto? Preferiría no crear un trabajo que se ejecute cada 'x' segundos/minutos/horas y verificar si necesito ejecutar el trabajo si puedo evitarlo.

También tengo curiosidad de por qué no veo ninguna información de registro relacionada con Quartz, pero ese es un problema secundario.

Aquí está mi configuración del resorte para la tarea:

<bean id="schedulerService" class="com.bah.pams.service.scheduler.SchedulerService"> 
    <property name="surveyResponseDao" ref="surveyResponseDao"/> 
    <property name="organizationDao" ref="organizationDao"/> 
</bean> 

<bean name="createSurveyResponsesJob" class="org.springframework.scheduling.quartz.JobDetailBean"> 
    <property name="jobClass" value="com.bah.pams.service.scheduler.jobs.CreateSurveyResponsesJob"/> 
    <property name="jobDataAsMap"> 
     <map> 
      <entry key="schedulerService" value-ref="schedulerService"/> 
     </map> 
    </property> 
</bean> 
<!-- Cron Trigger --> 
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> 
    <property name="jobDetail" ref="createSurveyResponsesJob"/> 
    <property name="cronExpression" value="0 0 0 1 * ? *"/> 
    <!--if the server is down at midnight on 1st of month, run this job as soon as it starts up next --> 
    <property name="misfireInstructionName" value="MISFIRE_INSTRUCTION_FIRE_ONCE_NOW"/> 
</bean> 

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 

    <property name="autoStartup" value="true"/> 

    <property name="quartzProperties"> 
     <props> 
      <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop> 
      <prop key="org.quartz.jobStore.misfireThreshold">60000</prop> 
     </props> 
    </property> 
    <property name="jobDetails"> 
     <list> 
      <ref bean="createSurveyResponsesJob"/> 
     </list> 
    </property> 

    <property name="triggers"> 
     <list> 
      <ref bean="cronTrigger"/> 
     </list> 
    </property> 
</bean> 

Respuesta

2

MISFIRE_INSTRUCTION_FIRE_ONCE_NOW es con el propósito que usted ha mencionado y si se sospecha de una parada del servidor (s) además se debería persistir sus puestos de trabajo fuera de la memoria de la JVM (por ejemplo, mediante el uso de JDBCJobStore en lugar de RAMJobStore).

RAMJobStore es rápido y liviano, pero toda la información de programación se pierde cuando finaliza el proceso.

http://quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigRAMJobStore

JDBCJobStore se utiliza para almacenar la información de programación (trabajo, triggers y calendarios) dentro de una base de datos relacional.

http://quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigJobStoreTX

espero que ayude.

0

Yo también he enfrentado el problema de querer ejecutar el último trabajo distribuido en un reinicio del servidor.

Esta es la solución que he encontrado es volver atrás un intervalo de tiempo para el gatillo y calcular lo que habría sido la próxima vez que se dispara. Al iterar a través de todos los factores desencadenantes, se puede determinar la hora más reciente que un disparador debería haber disparado en el pasado.


Calcular el intervalo entre cada disparo:

Date nextFireTime = trigger.getNextFireTime(); 
Date subsequentFireTime = trigger.getFireTimeAfter(nextFireTime); 
long interval = subsequentFireTime.getTime() - nextFireTime.getTime(); 

encontrar el siguiente tiempo de cocción durante un tiempo hasta que el intervalo en el pasado:

Date previousPeriodTime = new Date(System.currentTimeMillis() - interval); 
Date previousFireTime = trigger.getFireTimeAfter(previousPeriodTime); 

he encontrado que si está utilizando a CronTrigger esto le impide pedir un tiempo de fuego en el pasado.Para solucionar este modifico la hora de inicio, por lo que el fragmento anterior se convierte en:

Date originalStartTime = trigger.getStartTime(); // save the start time 
Date previousPeriodTime = new Date(originalStartTime.getTime() - interval); 
trigger.setStartTime(previousPeriodTime); 
Date previousFireTime = trigger.getFireTimeAfter(previousPeriodTime); 
trigger.setStartTime(originalStartTime); // reset the start time to be nice 

Iterar a través de todos los factores desencadenantes y encontrar la que es la más reciente en el pasado:

for (String groupName : scheduler.getTriggerGroupNames()) { 
    for (String triggerName : scheduler.getTriggerNames(groupName)) { 
     Trigger trigger = scheduler.getTrigger(triggerName, groupName); 
     // code as detailed above... 
     interval = ... 
     previousFireTime = ... 
    } 
} 

I' Lo dejaré como ejercicio al lector para refactorizarlo en métodos o clases de ayuda. De hecho, utilizo el algoritmo anterior en un desencadenante de delegación subclasificado que luego coloco en un conjunto ordenado por tiempos de disparo anteriores.

Cuestiones relacionadas