Scheduling Status
El propósito de esta página es aclarar los posibles estados de ejecución para los dos tipos diferentes de trabajos, así como cómo deben manejarse estos estados en el contexto de la rehidratación y el manejo de fallos. Los Execution Statuses se almacenan en una colección separada que se indexa por JobId y Timestamp, con el JobId correspondiente a una Job Specification válida en la colección Job Specification. Determinar si un trabajo es de una sola vez o recurrente puede hacerse mirando el schedulingSpecification (en Job Specification)
One Time Scheduled Job
Para un trabajo programado de una sola vez, aplican los siguientes Execution Statuses y la transición entre los estados es la siguiente:
Rehidratación - para trabajo programado de una sola vez
La rehidratación ocurre en el evento de una falla que provoca que Quartz se reinicie. Ya que no hay persistencia en Quartz, necesita rehidratarse con los trabajos que se han persistido en el Job Repository.
Los estados candidatos para rehidratación serían SCHEDULED
Recurrent Scheduled Job
Para un trabajo programado recurrente, aplican los siguientes Execution Statuses; la transición entre los estados es la siguiente:
Rehidratación - para trabajo programado recurrente
La rehidratación ocurre en el evento de una falla que provoca que Quartz se reinicie. Ya que no hay persistencia en Quartz, necesita rehidratarse con los trabajos que se han persistido en el Job Repository.
Los estados candidatos para rehidratación serían:
-
SCHEDULED
-
TRIGGERED
-
FAILED
Manejo de fallos de trabajos - para trabajo programado recurrente
Al determinar si los trabajos han fallado, necesitaríamos revisar los siguientes estados:
-
SCHEDULED
-
TRIGGERED
Y también el updatedTime de la colección JobExecutionStatus
Además de considerar el Execution Status también necesitamos considerar lo siguiente de JobSpecification
-
latestUpdate
-
schedulingSpecification
El latestUpdate debe compararse con el updatedTime en JobExecutionStatus; si latestUpdate > updatedTime entonces la schedulingSpecification debe considerarse como pendiente de ejecución, puede usar getNextValidTimeAfter usando latestUpdate comparando para ver si esto es consistente con la ejecución esperada.
De lo contrario, debe considerarse como un trabajo existente, es decir, el updateTime debe compararse con cronExpression - getNextValidTimeAfter; esto, junto con invocar el método contra el tiempo actual, puede usarse para determinar la ejecución fallida del trabajo comparando las dos fechas.
Por ejemplo:
//Successful job
//Daily expression with last job run time of 2022-11-18T08:24:00
// "Now": 2022-11-18T08:26:00
@Test
void shouldHaveAfterNowAndAfterLastJobRunResultSame() throws ParseException {
String dailyExpressionString = "0 24 08 * * ? *";
CronExpression dailyExpresssionJobRun = new CronExpression(dailyExpressionString);
LocalDateTime jobLastRunTime = LocalDateTime.parse("2022-11-18T08:24:00");
LocalDateTime nowTime = LocalDateTime.parse("2022-11-18T08:26:00");
Date nowDate = Date.from(nowTime.atZone(ZoneId.systemDefault()).toInstant());
Date nextValidTimeAfterNow = dailyExpresssionJobRun.getNextValidTimeAfter(nowDate);
Date jobLastRunDate = Date.from(jobLastRunTime.atZone(ZoneId.systemDefault()).toInstant());
Date nextValidTimeAfterJobRun = dailyExpresssionJobRun.getNextValidTimeAfter(jobLastRunDate);
String nextValidTimeAfterJobRunString = nextValidTimeAfterJobRun.toString();
System.out.println("next valid time after last run: " + nextValidTimeAfterJobRunString);
String nextValidTimeAfterNowString = nextValidTimeAfterNow.toString();
System.out.println("next valid time after now: " + nextValidTimeAfterNowString);
assertThat(nextValidTimeAfterJobRunString, is(nextValidTimeAfterNowString));
// next valid time after last run: Sat Nov 19 08:24:00 GMT 2022
// next valid time after now: Sat Nov 19 08:24:00 GMT 2022
}
//Failed job
//Daily expression with last job run time of 2022-11-17T08:24:00
// "Now": 2022-11-18T08:26:00
@Test
void shouldHaveAfterNowAndAfterLastJobRunResultDifferent() throws ParseException {
String dailyExpressionString = "0 24 08 * * ? *";
CronExpression dailyExpresssionJobRun = new CronExpression(dailyExpressionString);
LocalDateTime jobLastRunTime = LocalDateTime.parse("2022-11-17T08:24:00");
LocalDateTime nowTime = LocalDateTime.parse("2022-11-18T08:26:00");
Date nowDate = Date.from(nowTime.atZone(ZoneId.systemDefault()).toInstant());
Date nextValidTimeAfterNow = dailyExpresssionJobRun.getNextValidTimeAfter(nowDate);
Date jobLastRunDate = Date.from(jobLastRunTime.atZone(ZoneId.systemDefault()).toInstant());
Date nextValidTimeAfterJobRun = dailyExpresssionJobRun.getNextValidTimeAfter(jobLastRunDate);
String nextValidTimeAfterJobRunString = nextValidTimeAfterJobRun.toString();
System.out.println("next valid time after last run: " + nextValidTimeAfterJobRunString);
String nextValidTimeAfterNowString = nextValidTimeAfterNow.toString();
System.out.println("next valid time after now: " + nextValidTimeAfterNowString);
assertThat(nextValidTimeAfterJobRunString, not(is(nextValidTimeAfterNowString)));
// next valid time after last run: Fri Nov 18 08:24:00 GMT 2022
// next valid time after now: Sat Nov 19 08:24:00 GMT 2022
}