Crear trabajo de programación de servicios de alojamiento Quartz.NET fácilmente en base a la ASP.NET Core

En este artículo, te voy a mostrar cómo utilizar ASP.NET núcleo de servicios de alojamiento trabajos de ejecución Quartz.NET. La ventaja es que podemos controlar fácilmente el estado de funcionamiento de nuestro trabajo cuando se inicia la aplicación y paradas. A continuación, voy a demostrar cómo crear un simple IJob, una costumbre IJobFactoryy comenzó a funcionar en una aplicación en tiempo de ejecución QuartzHostedService. También voy a introducir una serie de cuestiones que requieren atención, a saber, el uso de los servicios en el ámbito de clase Singleton.

Autor: según Le deseo

dirección de inicio: https://www.cnblogs.com/yilezhu/p/12644208.html

Referencia Inglés Dirección: https://andrewlock.net/creating-a-quartz-net-hosted-service-with-asp-net-core/

Introducción - ¿Qué es Quartz.NET?

Al comienzo de lo que se introduce ante la mirada Quartz.NET en el siguiente diagrama que describe todo el núcleo básico de Quartz.NET contenido.

Nota: Esta imagen muestra suben objetivos Baidu para aprender a compartir, si la infracción, eliminar el contacto.

Quartz.NET

El siguiente desde su página web Descripción:

Quartz.NET es un sistema con todas las funciones de programación de trabajo de código abierto, desde el más adecuado para pequeñas aplicaciones a sistemas empresariales de gran tamaño.

Para muchos desarrolladores de ASP.NET, son los métodos preferidos utilizados en el temporizador se ejecuta tareas en segundo plano en un enfoque de grupo fiable. Quartz.NET ser utilizado junto con el ASP.NET Core también muy similar - porque el apoyo Quartz.NET .NET 2.0 estándar, por lo que puede utilizar fácilmente en su aplicación.

Quartz.NET Hay dos conceptos principales:

  • El Trabajo . Esta es una tarea de fondo que YAOAN un calendario específico en ejecución.
  • Planificador . Es responsable de, el plan basado en el tiempo a base de gatillo para ejecutar el trabajo.

ASP.NET Core por servicios de alojamiento tiene un buen apoyo para el funcionamiento de "una tarea de fondo." servicio gestionado cuando la aplicación ASP.NET Core comienza a iniciar y ejecutar el ciclo de vida de las aplicaciones de fondo inherente. Mediante la creación de un servicio de alojamiento Quartz.NET, puede utilizar aplicaciones estándar ASP.NET núcleo funcionando tareas en segundo plano.

Aunque puede crear un servicio de back-office "normales" (por ejemplo, cada 10 minutos para ejecutar una tarea), pero Quartz.NET proporciona una solución más robusta. Mediante el uso de disparadores Cron , puede asegurarse de que la tarea sólo en ciertos momentos del día (por ejemplo, 2:30 am) Ejecutar, o sólo una operación específica en unos pocos días, o cualquier combinación de la carrera. También le permite a agruparse ejecutar varias instancias de una aplicación a ejecutar una instancia (HA) únicamente en cualquier momento.

En este artículo, voy a cubrir los aspectos básicos de la creación de puestos de trabajo y Quartz.NET programado para estar en un temporizador que se ejecuta en servicio alojado.

Quartz.NET instalación

Quartz.NET es .NET Standard 2.0 paquete NuGet, es muy fácil de instalar en su aplicación. Para esta prueba, he creado un proyecto ASP.NET Core y seleccione la plantilla vacía. Puede dotnet add package Quartzinstalar el paquete Quartz.NET. Este punto de vista temporal del proyecto .csproj , será el siguiente:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Quartz" Version="3.0.7" />
  </ItemGroup>

</Project>

Crear un IJob

Para el trabajo práctico fondo estamos programados, pasaremos a la inyección ILogger<>para alcanzar los resultados y entonces la salida de la consola) escribe "Hola mundo" en. Debe darse cuenta de que contiene un único asíncronos Execute()métodos de interfaz de cuarzo IJob. Observamos aquí usamos la inyección de dependencias registrador es inyectado en el constructor.

using Microsoft.Extensions.Logging;
using Quartz;
using System;
using System.Threading.Tasks;

namespace QuartzHostedService
{
    [DisallowConcurrentExecution]
    public class HelloWorldJob : IJob
    {
        private readonly ILogger<HelloWorldJob> _logger;

        public HelloWorldJob(ILogger<HelloWorldJob> logger)
        {
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        public Task Execute(IJobExecutionContext context)
        {
            _logger.LogInformation("Hello world by yilezhu at {0}!",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            return Task.CompletedTask;
        }
    }
}

También utilicé [DisallowConcurrentExecution]las propiedades decoradas con el trabajo. Esta propiedad evita Quartz.NET intenta ejecutar el mismo trabajo al mismo tiempo .

Crear un IJobFactory

A continuación, tenemos que decirle cómo crear cuarzo IJobejemplo. Por defecto, cuarzo se utiliza Activator.CreateInstancepara crear instancia de trabajo, con el fin de llamar de manera efectiva new HelloWorldJob(). Por desgracia, ya que utilizamos la inyección de constructor, y por lo tanto no funciona. En su lugar, podemos proporcionar una costumbre IJobFactorygancho para ASP.NET Core contenedor de inyección de dependencias ( IServiceProvider) en:

using Microsoft.Extensions.DependencyInjection;
using Quartz;
using Quartz.Spi;
using System;

namespace QuartzHostedService
{
    public class SingletonJobFactory : IJobFactory
    {
        private readonly IServiceProvider _serviceProvider;

        public SingletonJobFactory(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
        }

        public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
        {
            return _serviceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob;
        }

        public void ReturnJob(IJob job)
        {
            
        }
    }
}

La planta será un IServiceProviderconstructor de pase, e implementar IJobFactoryla interfaz. Este es el método más importante es el NewJob()método. En este método, la planta debe devolver el programador de cuarzo solicitado IJob. En esta implementación, confiada a nosotros directamente IServiceProvidery dejar contenedor DI para encontrar la instancia deseada. Debido a GetRequiredServicela versión no genéricos devuelve un objeto, por lo que debe ser fundido al final IJob.

Este ReturnJobmétodo es los intentos planificador para retorno (es decir, destruir) los empleos locales creados por esta fábrica. Desafortunadamente, el uso de la incorporada en el IServiceProvidermecanismo no lo ha hecho. No podemos crear una nueva API adecuada requerida para el cuarzo IScopeService, sólo podemos crear un solo caso de un trabajo.

Esto es muy importante. Usando la aplicación anteriormente, sólo para crear una única forma de realización (o transitoria) la IJobaplicación es segura.

trabajos de configuración

Estoy IJobaquí para mostrar solamente una realización, sino que esperamos conseguir servicio de alojamiento universal de cuarzo es aplicable a cualquier número de puestos de trabajo. Para solucionar este problema, hemos creado un DTO sencilla JobSchedule, se utiliza para definir un tipo determinado puesto de trabajo del programa de temporizador:

using System;
using System.ComponentModel;

namespace QuartzHostedService
{
    /// <summary>
    /// Job调度中间对象
    /// </summary>
    public class JobSchedule
    {
        public JobSchedule(Type jobType, string cronExpression)
        {
            this.JobType = jobType ?? throw new ArgumentNullException(nameof(jobType));
            CronExpression = cronExpression ?? throw new ArgumentNullException(nameof(cronExpression));
        }
        /// <summary>
        /// Job类型
        /// </summary>
        public Type JobType { get; private set; }
        /// <summary>
        /// Cron表达式
        /// </summary>
        public string CronExpression { get; private set; }
        /// <summary>
        /// Job状态
        /// </summary>
        public JobStatus JobStatu { get; set; } = JobStatus.Init;
    }

    /// <summary>
    /// Job运行状态
    /// </summary>
    public enum JobStatus:byte
    {
        [Description("初始化")]
        Init=0,
        [Description("运行中")]
        Running=1,
        [Description("调度中")]
        Scheduling = 2,
        [Description("已停止")]
        Stopped = 3,

    }
}

Aquí JobTypeestá el trabajo del tipo .NET (en nuestro ejemplo es HelloWorldJob), y CronExpressiones un Quartz.NET la expresión Cron . expresiones cron permiten la programación compleja de un temporizador para que pueda establecer reglas complejas a continuación, por ejemplo, "Mensual No. 5 y No. 20 se activa una vez cada media hora entre las 8:00 a 10:00." Sólo asegúrese de comprobar el documento puede, porque no todos los sistemas operativos expresiones Cron se utilizan indistintamente.

Vamos a trabajar para agregar DI y Startup.ConfigureServices()configurar su horario:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Quartz;
using Quartz.Impl;
using Quartz.Spi;

namespace QuartzHostedService
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            //添加Quartz服务
            services.AddSingleton<IJobFactory, SingletonJobFactory>();
            services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
            //添加我们的Job
            services.AddSingleton<HelloWorldJob>();
            services.AddSingleton(
                 new JobSchedule(jobType: typeof(HelloWorldJob), cronExpression: "0/5 * * * * ?")
           );
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
           ......
        }
    }
}

Este código se añade al contenido como un solo cuatro a recipiente Ejemplo DI:

  • SingletonJobFactory Se ha descrito anteriormente, se utiliza para crear la instancia de trabajo.
  • Una ISchedulerFactoryaplicación, utilizando el built-in StdSchedulerFactory, que puede manejar la programación y gestión de trabajos
  • El HelloWorldJobtrabajo en sí
  • Un tipo HelloWorldJob, y comprende una de cinco segundos de una sola ejecución Cron expresión JobScheduleinstanciar objetos.

Ahora que hemos completado la mayor parte del trabajo básico, sólo falta una ellas combinan entre sí, QuartzHostedServicela.

La creación de QuartzHostedService

Esta QuartzHostedServicees IHostedServiceuna implementación de un conjunto de cuarzo planificador, y permitir que se ejecute en segundo plano. Debido a que el diseño de cuarzo, podemos IHostedServiceaplicar directamente, en lugar de partir de la base BackgroundServicese derivan de clase métodos más comunes . El código completo de los servicios enumerados a continuación, que más adelante se describirá en detalle.

using Microsoft.Extensions.Hosting;
using Quartz;
using Quartz.Spi;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace QuartzHostedService
{
    public class QuartzHostedService : IHostedService
    {
        private readonly ISchedulerFactory _schedulerFactory;
        private readonly IJobFactory _jobFactory;
        private readonly IEnumerable<JobSchedule> _jobSchedules;

        public QuartzHostedService(ISchedulerFactory schedulerFactory, IJobFactory jobFactory, IEnumerable<JobSchedule> jobSchedules)
        {
            _schedulerFactory = schedulerFactory ?? throw new ArgumentNullException(nameof(schedulerFactory));
            _jobFactory = jobFactory ?? throw new ArgumentNullException(nameof(jobFactory));
            _jobSchedules = jobSchedules ?? throw new ArgumentNullException(nameof(jobSchedules));
        }
        public IScheduler Scheduler { get; set; }

        public async Task StartAsync(CancellationToken cancellationToken)
        {
            Scheduler = await _schedulerFactory.GetScheduler(cancellationToken);
            Scheduler.JobFactory = _jobFactory;
            foreach (var jobSchedule in _jobSchedules)
            {
                var job = CreateJob(jobSchedule);
                var trigger = CreateTrigger(jobSchedule);
                await Scheduler.ScheduleJob(job, trigger, cancellationToken);
                jobSchedule.JobStatu = JobStatus.Scheduling;
            }
            await Scheduler.Start(cancellationToken);
            foreach (var jobSchedule in _jobSchedules)
            {
                jobSchedule.JobStatu = JobStatus.Running;
            }
        }

        public async Task StopAsync(CancellationToken cancellationToken)
        {
            await Scheduler?.Shutdown(cancellationToken);
            foreach (var jobSchedule in _jobSchedules)
            {
             
                jobSchedule.JobStatu = JobStatus.Stopped;
            }
        }

        private static IJobDetail CreateJob(JobSchedule schedule)
        {
            var jobType = schedule.JobType;
            return JobBuilder
                .Create(jobType)
                .WithIdentity(jobType.FullName)
                .WithDescription(jobType.Name)
                .Build();
        }

        private static ITrigger CreateTrigger(JobSchedule schedule)
        {
            return TriggerBuilder
                .Create()
                .WithIdentity($"{schedule.JobType.FullName}.trigger")
                .WithCronSchedule(schedule.CronExpression)
                .WithDescription(schedule.CronExpression)
                .Build();
        }
    }
}

La QuartzHostedServicedependencia de tres interdependientes: estamos Startupconfigurados en ISchedulerFactoryy IJobFactoryhay una IEnumerable<JobSchedule>. Solo agregamos a un contenedor DI JobScheduleobjetos (es decir HelloWorldJob), pero si usted se inscribe en más trabajo previsto en el envase DI, todos ellos se inyecte aquí (por supuesto, también se pueden obtener a través de la base de datos, junto con el control de la interfaz de usuario , no es lograr una programación visual de fondo de la misma? propia imaginación que ~).

StartAsyncEl método se llama cuando se inicia la aplicación, por lo que aquí es nuestra configuración lugar cuarzo. Nuestra una primera ISchedulerinstancia, a los atributos asignar para su uso posterior, y luego se inyectaron JobFactoryejemplos proporcionados al despachador:

 public async Task StartAsync(CancellationToken cancellationToken)
        {
            Scheduler = await _schedulerFactory.GetScheduler(cancellationToken);
            Scheduler.JobFactory = _jobFactory;
            ...
        }

A continuación, las operaciones de inyección de bucle planificar y uso definido al final de la clase para cada trabajo CreateJoby CreateTriggerayudar en la creación de un método de cuarzo IJobDetaily ITrigger. Si no te gusta esta parte de la obra, o la necesidad de configurar un mayor control, se puede ampliar según sea necesario JobSchedulepara personalizar fácilmente que DTO.

public async Task StartAsync(CancellationToken cancellationToken)
{
    // ...
   foreach (var jobSchedule in _jobSchedules)
            {
                var job = CreateJob(jobSchedule);
                var trigger = CreateTrigger(jobSchedule);
                await Scheduler.ScheduleJob(job, trigger, cancellationToken);
                jobSchedule.JobStatu = JobStatus.Scheduling;
            }
    // ...
}

private static IJobDetail CreateJob(JobSchedule schedule)
{
    var jobType = schedule.JobType;
    return JobBuilder
        .Create(jobType)
        .WithIdentity(jobType.FullName)
        .WithDescription(jobType.Name)
        .Build();
}

private static ITrigger CreateTrigger(JobSchedule schedule)
{
    return TriggerBuilder
        .Create()
        .WithIdentity($"{schedule.JobType.FullName}.trigger")
        .WithCronSchedule(schedule.CronExpression)
        .WithDescription(schedule.CronExpression)
        .Build();
}

Por último, una vez que todos los trabajos se han programado, se le puede llamar Scheduler.Start()para hacer frente al proceso de planificación Quartz.NET inicio real en el fondo. Cuando se cierra la aplicación, el marco llamará StopAsync(), y se puede llamar Scheduler.Stop()con el fin de cerrar de forma segura el proceso planificador.

public async Task StopAsync(CancellationToken cancellationToken)
{
    await Scheduler?.Shutdown(cancellationToken);
}

Se puede utilizar AddHostedService()un método de extensión de servicios gestionados Startup.ConfigureServicesen nuestros servicios de back office:

public void ConfigureServices(IServiceCollection services)
{
    // ...
    services.AddHostedService<QuartzHostedService>();
}

Si ejecuta la aplicación, debería ver una vez cada 5 segundos para ejecutar tareas en segundo plano y escribir la consola (o en cualquier registro de configuración)

imagen-20200406151153107

Utilice el alcance del servicio en el trabajo

Se describe en este artículo para lograr un gran problema: Sólo puede crear Singleton o transitoria trabajo. Esto significa que no puede utilizar registrado para el alcance de las dependencias de servicio. Por ejemplo, usted no será capaz de EF núcleo de DatabaseContextinyección de su IJobaplicación, ya que se encontrará prisionero Dependencia problema.

No es difícil de resolver este problema: Usted puede inyectar IServiceProvidery crear su propio ámbito. Por ejemplo, si necesita HelloWorldJobutilizar el alcance del servicio, puede utilizar lo siguiente:

public class HelloWorldJob : IJob
{
    // 注入DI provider
    private readonly IServiceProvider _provider;
    public HelloWorldJob( IServiceProvider provider)
    {
        _provider = provider;
    }

    public Task Execute(IJobExecutionContext context)
    {
        // 创建一个新的作用域
        using(var scope = _provider.CreateScope())
        {
            // 解析你的作用域服务
            var service = scope.ServiceProvider.GetService<IScopedService>();
            _logger.LogInformation("Hello world by yilezhu at {0}!",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
        }

        return Task.CompletedTask;
    }
}

Esto asegura que ambos crean un nuevo ámbito cada vez que se ejecuta el trabajo, por lo que puede IJobrecuperar (y tratar con) el alcance del servicio. Por desgracia, el texto es de hecho una cierta confusión. En el siguiente artículo, te voy a mostrar otra manera de lograr una más elegante, es más concisa, los interesados pueden seguir la primera vez en "DotNetCore real" número público para las actualizaciones.

resumen

En este artículo, introduje Quartz.NET, y muestra cómo utilizarlo en ASP.NET núcleo de IHostedServicelos trabajos de programación de fondo. El ejemplo mostrado en este artículo, el singleton adecuada la mayor parte o la operación transitoria, que no es ideal, porque el uso del alcance de servicio es muy torpe. En el siguiente artículo, te voy a mostrar otra manera de lograr una más elegante, es más concisa, y hace que sea más fácil utilizar el alcance del servicio, los interesados pueden seguir la primera vez en "DotNetCore real" número público para las actualizaciones.

Supongo que te gusta

Origin www.cnblogs.com/yilezhu/p/12644208.html
Recomendado
Clasificación