2009-12-19 8 views
21

Para mi aplicación, creo trabajos y los programo con CronTriggers. Cada trabajo tiene solo un disparador y tanto el nombre del trabajo como los nombres de los activadores son los mismos. Ningún trabajo comparte un disparador.Quartz Java reanudar un trabajo lo excede muchas veces

Ahora cuando creo un disparador de cron como este "0/1 * * * *?" que ordena al trabajo ejecutar cada segundo, funciona bien.

El problema se levanta cuando por primera vez una pausa en el trabajo llamando a:

scheduler.pauseJob(jobName, jobGroup); 

y luego reanudar el trabajo después de digamos 50 segundos con:

scheduler.resumeJob(jobName, jobGroup); 

lo que veo es que para estos 50 segundos el trabajo no se ejecutó según lo solicitado. ¡Pero en el momento en que reanudo el trabajo, veo 50 ejecuciones del trabajo al mismo tiempo!

pensé que esto era debido a la configuración predeterminada para la instrucción de fallo de encendido pero incluso después de ajustar instruciton fallo de encendido del gatillo sobre la creación de esta:

trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING); 

La misma cosa sucede. ¿Alguien puede sugerir una forma de arreglar esto?

Respuesta

27

El CronTrigger funciona recordando el nextFireTime. Después de crear el activador, se inicializa el nextFireTime. Cada vez que se desencadena el trabajo nextFireTime se actualiza. Dado que el trabajo no se activa cuando el nextFireTime en pausa permanece "viejo". Entonces, después de reanudar el trabajo, el activador devolverá cada tiempo de disparo anterior.

El problema es que el disparador no sabe que se está pausando. Para superar esto existe este manejo de fallo de encendido. Después de reanudar los trabajos, se invocará el método updateAfterMisfire() del desencadenante que corrige el nextFireTime. Pero no si la diferencia entre nextFireTime y ahora es menor que misfireThreshold. Entonces el método nunca se llama. El valor predeterminado de este umbral es 60,000. Por lo tanto, si su período de pausa fuera mayor de 60 años, todo estaría bien.

Como usted tiene problemas, asumo que no es así. ;) Para solucionar esto se puede modificar el umbral o utilizar un simple envoltorio alrededor CronTrigger:

public class PauseAwareCronTrigger extends CronTrigger { 
    // constructors you need go here 

    @Override 
    public Date getNextFireTime() { 
     Date nextFireTime = super.getNextFireTime(); 
     if (nextFireTime.getTime() < System.currentTimeMillis()) { 
      // next fire time after now 
      nextFireTime = super.getFireTimeAfter(null); 
      super.setNextFireTime(nextFireTime); 
     } 
     return nextFireTime; 
    } 
} 
+4

Muchas gracias :) esto funcionó como un encanto. Parece extraño que una tarea tan simple como detener un trabajo pueda crear problemas como este. –

5

Si pausa el trabajo, el disparador continuará disparando, pero las ejecuciones se pondrán en cola hasta que se reanude el trabajo. Esto no es un desencadenador de fallas, por lo que la configuración no tendrá ningún efecto.

Lo que quiere hacer, creo, es deshabilitar programáticamente o eliminar el desencadenador cron, en lugar de detener el trabajo. Cuando desee reanudar, vuelva a agregar el desencadenador.

+0

El método javadoc para el método pauseJob dice "Ponga en pausa JobDetail con el nombre dado, pausando todos sus activadores actuales". así que supongo que el gatillo está en pausa. Además, no hay un método de pausa en el disparador. O cualquier cosa que se le parezca. ¿Simplemente quitar el activador del trabajo y volver a insertarlo es mi única opción para pausar un trabajo? Quiero decir que esto es algo bastante trivial para querer que su programador lo haga. ¿Cómo es que no funciona? –

+0

Hmm, buen punto. Me parece que con Quartz, probar varias cosas hasta que algo funciona es el enfoque más productivo, ya que no siempre hace lo que dice en la lata. – skaffman

+0

Esto es extremadamente frustrante ya que tampoco hay una manera fácil de simplemente quitar un disparador del trabajo. ¿Puedo tener un trabajo sin gatillo? y si es así, ¿cómo? ¿Algunas ideas? Estoy empezando a perder la paciencia con esto, lo he intentado durante horas :) –

1

Desde 1.6.5 al menos (la versión más antigua de cuarzo en mis manos), el programador tiene un método que pauseTrigger toma el nombre/grupo como parámetros. Esto significa que no tiene que tener una subclase de cada tipo de activador que use, ni tiene que hacer trucos de eliminación/inserción de funky.

Ambos son importantes para mí porque 1) nuestra base de datos tiene una política estricta de no eliminar y 2) el almacén de datos personalizado que utilizo no admite las subclases de activación.

Cuestiones relacionadas