Fala filhotes! Hoje vou passar uma dica legal para vocês. Bom, um dia desses tive que criar um Windows Service aqui no serviço ( nada demais ) que roda em determinados dias / horários, então eu me perguntei: “qual a melhor maneira de fazer isso”? O que eu costumava fazer era criar um Timer e um TimerCallback com um período especifico para chamar o meu método, mas há casos em que você quer um controle maior como só executar em finais de semana ou somente em alguns dias específicos.

Batch Jobs

Se você já trabalhou com mainframe você deve lembrar dos Batch Jobs, eles são nada mais nada menos que Jobs que executam em algum horário / dia especifico, sendo que na maioria das vezes é fora do horário de pico já que normalmente utilizam muito processamento. Eu precisava dessa funcionalidade no meu serviço, foi ai que vasculhando a internet eu acabei achando uma biblioteca que me oferecia justamente isso: a Quartz .NET.

Quartz .NET

Essa biblioteca permite a você criar e agendar Jobs de forma simples e rápida. O funcionamento é bem básico consistindo em 3 componentes: o Scheduler, a Trigger e o Job.

Scheduler (Agendador): O Scheduler como o nome já diz, é o responsável por agendar os Jobs, ou seja, é o componente que associa a Trigger ao Job, inicia ou para as tarefas.

Trigger (Gatilho): É o responsável pelo “cronograma“ do Job, ou seja nele que ficara a informação que o Job só roda de segunda a quarta por exemplo.

Job: Um Job nesse caso é uma classe. Qualquer classe pode ser um Job, basta implementar a interface IJob e o método Execute.

Exemplos:

Bom, segue alguns exemplos de como você usa o Quartz .NET:

    protected override void OnStart(string[] args)
        {
            // Constroi uma scheduler factory
            ISchedulerFactory schedFact = new StdSchedulerFactory();

            // Pego o Scheduler
            IScheduler sched = schedFact.GetScheduler();

            sched.Start();

            // Crio um JobDetail com o nome do Job ( lembrete ) o grupo (grupoLembrete) e o tipo (tipo da minha classe do Job )
            // Você pode ter um controle dos Jobs por grupos, mas não é necesssario ter um grupo.
            JobDetail jobDetail = new JobDetail("lembrete", "grupoLembrete", typeof(JobLembrete));

            // Crio uma Trigger que sera executada diariamente
            Trigger trigger = TriggerUtils.MakeDailyTrigger(int.Parse(triggerTime[0]), int.Parse(triggerTime[1]));

            // Nome da Trigger
            trigger.Name = "minhaTrigger";
            // Agendo o Job ( passando a trigger também )
            sched.ScheduleJob(jobDetail, trigger);
        }

Lembrando que o JobLembrete (Minha classe do Job) tem que implementar a IJob:

public class JobLembrete : IJob
    {
        #region IJob Members
        public void Execute(JobExecutionContext context)
        {
        }
    }

Como você pode ver a Trigger determina o horário que o Job vai executar, nesse caso diariamente, mas você pode executar hora por hora, em dias específicos ou apenas uma vez. Vamos a mais alguns exemplos:

// HolidayCalendar é um calendario onde você define os feriados. Dias que seu Job não irá rodar
            HolidayCalendar holidays = new HolidayCalendar();

            // Adicionamos o Natal
            DateTime natal = new DateTime(DateTime.UtcNow.Year, 12, 25);
            holidays.AddExcludedDate(natal);
            
            // Dia da Independencia
            DateTime independencia = new DateTime(DateTime.UtcNow.Year, 9, 7);
            holidays.AddExcludedDate(independencia);
            
            // Passa o calendario de feriados
            sched.AddCalendar("holidays", holidays, false, false);
            
            // O job ira começar a ser executado dia 16/06 as 8 da manhã
            DateTime runDate = new DateTime(DateTime.UtcNow.Year, 06, 16, 8, 0, 0).ToUniversalTime();

            JobDetail job = new JobDetail("job1", "group1", typeof(SimpleJob));
            
            // Você pode usar a SimpleTrigger tambem. Aqui o job executara para sempre de 1 em 1 hora.
            SimpleTrigger trigger = new SimpleTrigger("trigger1", "group1", runDate, null, SimpleTrigger.RepeatIndefinitely, TimeSpan.FromHours(1));

            // A trigger irá obdecer o nosso calendario.
            trigger.CalendarName = "holidays";
            
            // Agenda o job e ja pega a data da primeira vez que IRÁ executar.
            DateTime firstRunTime = sched.ScheduleJob(job, trigger);

            // Crio um novo job que ira executar independente do calendario            
            JobDetail job2 = new JobDetail("job2", "group1", typeof(SimpleJob));
            
            // Esse job irá executar apenas nas PRIMEIRAS SEGUNDA FEIRAS de todo mês as 10 da manhã 
            var mondayTrigger = new CronTrigger("trigger2", "group1", "job2", "group1", "0 0 10 ? * MON#1");

            sched.ScheduleJob(job2, mondayTrigger);

Viram a ultima expressão que usei no CronTrigger? Pois é, esse componente me da a possibilidade de controle total do meu Job. Prometo explicar todas as possibilidades do CronTrigger e muito mais coisas do Quartz .Net, mas para evitar que o post fique muito longo vamos finalizar por aqui.

Conclusão

O Quartz .Net é tão fácil de usar que pode ser implementado em qualquer ocasião, do mais simples ao mais complexo!

Atualizado:

Para mais informações sobre a biblioteca acesse o site http://quartznet.sourceforge.net/. Lá tem vários tutoriais e a documentação completa.