En Quartz.NET, ¿hay alguna manera de establecer una propiedad que solo permita la ejecución de una instancia de un trabajo?
(4)
Bueno, una manera simple de hacerlo sería simplemente almacenar un valor de indicador en alguna variable, y verificar la variable al ingresar al método de trabajo.
De esa manera, simplemente dejarías que el trabajo "comenzara" por segunda vez, simplemente saldría inmediatamente sin hacer ningún trabajo real.
Aquí hay un ejemplo:
private volatile bool _IsRunning;
...
if (Interlocked.Exchange(ref _IsRunning, true))
return;
try
{
// job code
}
finally
{
_IsRunning = false;
}
Tengo un servicio que se ejecutará cada X minutos. Si ese trabajo lleva más de X minutos por algún motivo imprevisto, quiero asegurarme de que el activador no dé inicio a una segunda instancia de este trabajo.
Escenario de muestra
- Tengo Job X, recoge archivos y Quartz lo activa cada 1 minuto.
- Job X normalmente puede procesar 100 archivos en 1 minuto, cualquier cosa que supere los 100 archivos llevará más de 1 minuto.
- Desde el último tiempo de ejecución, 150 archivos están disponibles, por lo que Job X arranca y comienza a procesarse. Cuando se llega a 1 minuto, se procesaron 100 archivos, quedan 50 archivos y Job X continúa ejecutándose.
- Sin embargo, se inicia una segunda instancia de Job X porque el disparador se dispara cada 1 minuto.
- Ahora tengo 2 instancias de Job X recogiendo los mismos 50 archivos.
¿Hay alguna manera de cablear Quartz.NET para permitir solo 1 instancia de un trabajo? Estoy bien con el segundo gatillo esperando que el primero se complete o también estoy de acuerdo con una opción para que omita el segundo activador, ya que se activará de nuevo en un minuto.
Eché un vistazo a la versión Java de Quartz API y encontré una propiedad '' DisallowConcurrentExecution '' pero no encontré ninguna similar en la versión .NET.
Mi código para la implementación de Quartz.NET
public IScheduler Scheduler { get; set; }
public IJobListener AutofacJobListener { get; set; }
public void Start()
{
var trigger = TriggerUtils.MakeMinutelyTrigger(1);
trigger.Name = @"Document Import Trigger";
Scheduler.ScheduleJob(new JobDetail("Document Import", null, typeof(DocumentImportJob)), trigger);
Scheduler.AddGlobalJobListener(AutofacJobListener);
Scheduler.Start();
}
Como una actualización de esta respuesta, en las versiones más recientes de Quartz.Net, esto se hace ahora a través de un atributo "DisallowConcurrentExecution" que aplica a la implementación de su trabajo:
[DisallowConcurrentExecution]
public class MyJob : IJob
{
..
}
Y para la instrucción de fallo de encendido, aquí está cómo hacerlo:
var trigger = TriggerBuilder.Create()
.WithSimpleSchedule(ssb => ssb.WithIntervalInMinutes(interval)
.RepeatForever()
.WithMisfireHandlingInstructionIgnoreMisfires()
)
.Build();
Use el atributo DisallowConcurrentExecution.
Declara tu clase de la siguiente manera:
[DisallowConcurrentExecution]
public class SomeTask : IJob
{
}
Fallas
"Instrucciones de fallo de encendido Otra propiedad importante de un disparador es su" instrucción de fallo de encendido ". Se produce un fallo de encendido si un disparador persistente" pierde "su tiempo de disparo debido a que el planificador se apaga o porque no hay hilos disponibles en el grupo de subprocesos de Quartz.NET ejecutando el trabajo. Los diferentes tipos de disparadores tienen diferentes instrucciones de fallas disponibles para ellos. Por defecto usan una instrucción de ''política inteligente'' - que tiene un comportamiento dinámico basado en el tipo de activación y configuración. Cuando el programador se inicia, busca cualquier activador persistente que han fallado, y luego actualiza cada uno de ellos en función de sus instrucciones de fallo de encendido configuradas individualmente. Cuando empiece a utilizar Quartz.NET en sus propios proyectos, debe familiarizarse con las instrucciones de fallo de encendido que se definen en los tipos de activador dados, y explicó en su documentación de API. Se proporcionará información más específica acerca de las instrucciones de fallas de encendido dentro de las lecciones tutoriales específicas para cada disparador tipo."
Consulte la información sobre "instrucciones de fallo de disparo" en la parte inferior de estas páginas:
Respuesta de Old Quartz.NET API:
http://quartznet.sourceforge.net/apidoc/topic142.html :
Las instancias de IStatefulJob siguen reglas ligeramente diferentes de las instancias regulares de IJob. La diferencia clave es que su JobDataMap asociado se reintenta después de cada ejecución del trabajo, preservando así el estado para la próxima ejecución. La otra diferencia es que no se permite que los trabajos con estado se ejecuten al mismo tiempo , lo que significa que los nuevos activadores que se producen antes de que se complete el método IJob.Execute se retrasarán.
Por lo tanto, declare su clase ''Trabajo'' de la siguiente manera:
class DocumentImportJob : IStatefulJob
{
......
}
Para evitar tareas retrasadas, volver a disparar inmediatamente después de que finalice el trabajo (cuando el trabajo demora más de 1 minuto y provoca un ''fallo de disparo''), haga lo siguiente al crear sus disparadores (ajuste según el tipo de disparador utilizado):
myJobTrigger.MisfireInstruction = MisfireInstruction.CronTrigger.DoNothing;
https://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/more-about-triggers.html
bool público Validar (IJobExecutionContext context) {
if (context.Scheduler.GetCurrentlyExecutingJobs().Any(x => x.FireInstanceId != context.FireInstanceId
&& x.JobDetail.Key == context.JobDetail.Key))
{
return true;
}
else
{
return false;
}
}