2011-09-12 23 views
6

¿Es posible registrar un trabajo de cuarzo para usar siempre la misma instancia de IJob inyectada por DI container Unity? Tengo una instancia única "Monitor" de una clase Monitor procedente de la Unidad DI, cosa que me registré como:Quartz, Unity & .NET

container.RegisterType<IMonitor, Monitor>(new ContainerControlledLifetimeManager()) 

y mi IJob aplicación espera tener esa instancia del monitor se inyecta en ella:

class MyJob : IJob { 
... 
[Dependency] IMonitor monitor {get; set;} 
... 
void Execute() 
... 
} 

pero cuando se activan los eventos de cuarzo, se llama a la implementación IJob.Execute() antes de inyectar la dependencia. ¿Cómo debo hacer que esto funcione? ¿Debería considerar otros contenedores DI o Schedulers en su lugar?

Gracias

Respuesta

5

cuarzo se reinstantiate implementación de la interfaz de trabajo en cada caso de incendio. Es recommended utilizar IStatefulJob si desea conservar el estado entre las ejecuciones de empleo

casos IStatefulJob siguen reglas ligeramente diferentes de instancias regulares 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 los trabajos con estado no se pueden ejecutar simultáneamente, lo que significa que los nuevos desencadenantes que se producen antes de que se complete el método IJob.Execute serán diferidos.

De Cuarzo tutorial:

StatefulJob

Ahora, algunas notas adicionales sobre los datos del estado de un trabajo (aka JobDataMap): Una instancia de trabajo se puede definir como "estado" o "no -estable ". Los trabajos no estatales solo tienen su JobDataMap almacenado en el momento en que se agregan al planificador. Esto significa que cualquier cambio realizado en el contenido del mapa de datos del trabajo durante la ejecución del trabajo se perderá, y no será visto por el trabajo la próxima vez que se ejecute. Tiene probablemente adivinado, un trabajo con estado es todo lo contrario - su JobDataMap se vuelve a almacenar después de cada ejecución del trabajo. Un efecto secundario de que hace que un trabajo sea estable es que no se puede ejecutar al mismo tiempo. O en otras palabras: si un trabajo es con estado, y un disparador intenta 'disparar' el trabajo mientras ya se está ejecutando, el disparador bloqueará (espera) hasta que se complete la ejecución anterior.

Usted 'marca' un trabajo como con estado al hacer que implemente la interfaz StatefulJob , en lugar de la interfaz del trabajo.

Otra opción para usted es implementar su propio JobFactory:

'instancias' empleo

Un punto final sobre este tema que pueden o no ser obvio: Usted puede crear un único tipo de tarea y almacenar muchos 'ejemplo definiciones' de la misma dentro del planificador mediante la creación de varias instancias de JobDetails - cada uno con su propio conjunto de propiedades y JobDataMap - y añadiendo todos ellos al programador.

Cuando se dispara un disparador, el Trabajo al que está asociado se crea mediante JobFactory configurado en el Programador. La JobFactory predeterminada simplemente llama a newInstance() en la clase de trabajo. Es posible que desee crear su propia implementación de JobFactory para realizar cosas como con el contenedor IoC o DI de su aplicación producir/inicializar la instancia de trabajo .

+0

Bueno, no estoy interesado en la celebración en la misma instancia IJob, lo que quiero es tener la misma IMonitor inyectado en cada nueva instancia IJob ... – j040p3d20

+2

tienda la referencia a su 'Monitor' en JobDataMap o implemente su propia JobFactory. – Dmitry

+0

La interfaz 'StatefulJob' ha quedado en desuso ... recomienda utilizar anotaciones http://quartz-scheduler.org/documentation/quartz-2.x/new-in-quartz-2 – Jaider

2

Puede hacerlo implementando su propia JobFactory. Vas a tener que implementar la interfaz IJobFactory:

public interface IJobFactory 
{ 
    /// <summary> 
    /// Called by the scheduler at the time of the trigger firing, in order to 
    /// produce a <see cref="IJob" /> instance on which to call Execute. 
    /// </summary> 
    /// <remarks> 
    /// <p> 
    /// It should be extremely rare for this method to throw an exception - 
    /// basically only the the case where there is no way at all to instantiate 
    /// and prepare the Job for execution. When the exception is thrown, the 
    /// Scheduler will move all triggers associated with the Job into the 
    /// <see cref="TriggerState.Error" /> state, which will require human 
    /// intervention (e.g. an application restart after fixing whatever 
    /// configuration problem led to the issue wih instantiating the Job. 
    /// </p> 
    /// 
/// </remarks> 
    /// <param name="bundle"> 
    /// The TriggerFiredBundle from which the <see cref="JobDetail" /> 
    /// and other info relating to the trigger firing can be obtained. 
    /// </param> 
    /// <throws> SchedulerException if there is a problem instantiating the Job. </throws> 
    /// <returns> the newly instantiated Job 
    /// </returns> 
    IJob NewJob(TriggerFiredBundle bundle); 
} 

A continuación, establezca la propiedad quartz.scheduler.jobFactory.type del planificador para el tipo de su fábrica de trabajo.

Como referencia, aquí está la fábrica de trabajo predeterminada que utiliza quartz.net:

public class SimpleJobFactory : IJobFactory 
{ 
    private static readonly ILog Log = LogManager.GetLogger(typeof (SimpleJobFactory)); 

    /// <summary> 
    /// Called by the scheduler at the time of the trigger firing, in order to 
    /// produce a <see cref="IJob" /> instance on which to call Execute. 
    /// </summary> 
    /// <remarks> 
    /// It should be extremely rare for this method to throw an exception - 
    /// basically only the the case where there is no way at all to instantiate 
    /// and prepare the Job for execution. When the exception is thrown, the 
    /// Scheduler will move all triggers associated with the Job into the 
    /// <see cref="TriggerState.Error" /> state, which will require human 
    /// intervention (e.g. an application restart after fixing whatever 
    /// configuration problem led to the issue wih instantiating the Job. 
/// </remarks> 
    /// <param name="bundle">The TriggerFiredBundle from which the <see cref="JobDetail" /> 
    /// and other info relating to the trigger firing can be obtained.</param> 
    /// <returns>the newly instantiated Job</returns> 
    /// <throws> SchedulerException if there is a problem instantiating the Job. </throws> 
    public virtual IJob NewJob(TriggerFiredBundle bundle) 
    { 
     JobDetail jobDetail = bundle.JobDetail; 
     Type jobType = jobDetail.JobType; 
     try 
     { 
      if (Log.IsDebugEnabled) 
      { 
       Log.Debug(string.Format(CultureInfo.InvariantCulture, "Producing instance of Job '{0}', class={1}", jobDetail.FullName, jobType.FullName)); 
      } 

      return (IJob) ObjectUtils.InstantiateType(jobType); 
     } 
     catch (Exception e) 
     { 
      SchedulerException se = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Problem instantiating class '{0}'", jobDetail.JobType.FullName), e); 
      throw se; 
     } 
    } 
} 

La línea interesante es:

return (IJob) ObjectUtils.InstantiateType(jobType); 
5

Tenga una mirada en Quartz.Unity.

https://www.nuget.org/packages/Quartz.Unity/1.0.1

Doc es muy escasa, pero parece que todo lo que tiene que hacer es añadir el paquete Nuget y la siguiente línea a la configuración del contenedor.

var container = new UnityContainer().AddNewExtension<Quartz.Unity.QuartzUnityExtension>(); 
0

Cree un CustomJobfactory que anule SimpleJobFactory y use spring para crear instancias de las clases de trabajo.

/// <summary> 
/// Custom Job Factory 
/// </summary> 
public class CustomJobFactory : SimpleJobFactory 
{ 
    /// <summary> 
    /// Application context 
    /// </summary> 
    private IApplicationContext context; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="CustomJobFactory" /> class. 
    /// </summary> 
    public CustomJobFactory() 
    { 
     this.context = ContextRegistry.GetContext(); 
    } 

    /// <summary> 
    /// Creates a new job instance 
    /// </summary> 
    /// <param name="bundle">Trigger bundle</param> 
    /// <param name="scheduler">Job scheduler</param> 
    /// <returns></returns> 
    public override IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) 
    { 
     IJobDetail jobDetail = bundle.JobDetail; 
     Type jobType = jobDetail.JobType; 
     return this.context.GetObject(jobType.Name) as IJob; 
    } 

    /// <summary> 
    /// Return job 
    /// </summary> 
    /// <param name="job">Job instance</param> 
    public override void ReturnJob(IJob job) 
    { 
    } 
}