image

Implementar tarefas de fundo dificilmente poderia ser mais simples com ASP.NET Core hoje. Mas quando se trata de agendar tarefas de fundo, o que você faz? Como se vê, você tem uma série de opções muito atraentes disponíveis para você. Especificamente, estou pensando:

  • Serviço hospedado do ASP.NET Core
  • Quartz.NET
  • Elsa Workflows (a razão pela qual você está lendo este post)

Vamos dar uma breve olhada em cada uma dessas opções para ver como elas se comparam.

Serviço hospedado

Se tudo o que vocêeprecisa é de uma tarefa recorrente que ex cutes em um intervalo definido, a opção mais simples (sem assumir quaisquer dependências de pacotes externos) pode ser implementar um Serviço Hospedado e executar o trabalho em um loop infinito até que o token de cancelamento seja acionado.

Por exemplo:

// Do some work every minute.
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
  while(!stoppingToken.IsCancellationRequested)
  {
     // Do work.
     
     // Wait for a minute.
     await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
  }
}

RecurringTask.snippet.cs hosted with ❤ by GitHub

Isso é perfeitamente bom para realizar trabalhos em segundo plano em um intervalo específico. Mas e se você quiser agendar o trabalho usando horários mais avançados, como usar um cronograma de cron?

Como demonstrado neste artigo,você pode implementar isso como um serviço hospedado você mesmo. Mas isso requer um pouco de código.

E quanto Quartz.NET?

Quartz.NET

Quartz.NET é um sistema de agendamento de código aberto para .NET que é flexível e fácil de usar. Ele oferece muitos recursos que tornam o agendamento de trabalhos super fácil.

Com Quartz.NET, você tem todos os tipos de opções de agendamento na forma de gatilhos, que incluem gatilhos simples e gatilhos de cron.

Para implementar um trabalho que seja executado em um determinado cronograma, tudo o que você precisa fazer é implementar uma classe de Trabalho que realize o trabalho, registrá-lo com quartzo e, em seguida, programá-lo usando um ou mais gatilhos.

Por exemplo:

services.AddQuartz(quartz => 
{
  quartz.AddJob<MyJob>(j => j.WithIdentity("MyJob"));
  
  quartz.AddTrigger(t => t
    .ForJob("MyJob")
    .StartNow()
    .WithCronSchedule("* * * * * * *"));
});

class MyJob : IJob
{
   public Task Execute(IJobExecutonContext context)
   {
      // Do work.
   }
}

QuartzJob.snippet.cs hosted with ❤ by GitHub

Isso pode ser tudo que você precisa para implementar trabalhos programados.

Mas há uma terceira opção que torna isso mais fácil, flexível e ainda mais poderoso.

Elsa Workflows

Elsa Workflows é uma biblioteca de código aberto para .NET que permite que os aplicativos implementem fluxos de trabalho de curto e longo prazo, seja em código, usando um designer ou ambos.

Mesmo que você não tenha interesse em trabalhar com sistemas de fluxo de trabalho e designers, Elsa vem com uma API fácil de usar para implementar tarefas de fundo. O equivalente elsa de um Serviço Hospedado em .NET Core e um Job in Quartz.NET é o Workflow.

Na verdade, o mecanismo de agendamento da Elsa Workflows usa diretamente Quartz.NET para agendar o trabalho em um determinado momento.

Para implementar um fluxo de trabalho, tudo o que você precisa fazer é implementá-lo e registrá-lo com DI. É isso, é isso. IWorkflow

Por exemplo, para implementar um trabalho agendado, você pode criar o seguinte fluxo de trabalho:

class MyJob : IWorkflow
{
  public void Build(IWorkflowBuilder workflow)
  {
    workflow
      .Cron("* * * * * * *")
      .WriteLine(() => $"CRON event at {DateTime.Now}");
  }
}

ElsaWorkflows.snippet.cs hosted with ❤ by GitHub

E então registre-o com DI assim:

services
   .AddElsa()
   .AddWorkflow<MyJob>();

Sim, isso é muito fácil.

Claro, a maioria dos trabalhos de fundo fará um pouco mais do que apenas imprimir a data e a hora atuais para o console. Por exemplo, você pode querer limpar o lixo todas as segundas-feiras de manhã às 08:00:

class CleanTrash : IWorkflow
{
  private ITrashCleanupService _cleanupService;

  public CleanTrash(ITrashCleanupService cleanupService)
  {
    _cleanupService = cleanupService;
  }

  public void Build(IWorkflowBuilder workflow)
  {
    workflow
      .Cron("0 0 8 ? * MON *")
      .Then(CleanoutTrash);
  }
  
  private async ValueTask CleanoutTrash(ActivityExecutionContext context)
  {
    await _cleanupService.CleanupTrashAsync(context.CancellationToken);
  }
}

ElsaWorkflows.snippet.cs hosted with ❤ by GitHub

Parece bem arrumado!

Não só elsa simplifica declarar tarefas programadas com esta simples API, ela abre automaticamente a porta para você implementar coisas reais de fluxo de trabalho (já que afinal, este é um fluxo de trabalho real!).

Por exemplo, depois de limpar o lixo, você pode querer dormir por um tempo, passear com o cachorro e lavar alguns pratos, talvez algo assim:

class ThisIsMyMonday : IWorkflow
{
  private ITrashCleanupService _cleanupService;
  private IDogWalkingService _dogWalkingService;
  private IDishCleaningService _dishCleaningService;

  public CleanTrash(ITrashCleanupService cleanupService, IDogWalkingService dogWalkingService, IDishCleaningService dishCleaningService)
  {
    _cleanupService = cleanupService;
    _dogWalkingService = dogWalkingService;
    _dishCleaningService = dishCleaningService;
  }

  public void Build(IWorkflowBuilder workflow)
  {
    workflow
      .Cron("0 0 8 ? * MON *")
      .Then(CleanoutTrash)
      .Timer(Duration.FromHours(2)) // Sleep for 2 hours
      .Then(WalkTheDog)
      .Then(DoTheDishes); 
  }
  
  private ValueTask CleanoutTrash(ActivityExecutionContext context) => _cleanupService.CleanupTrashAsync(context.CancellationToken);
  private ValueTask WalkTheDog(ActivityExecutionContext context) => _dogWalkingService.WalkTheDogAsync(context.CancellationToken);
  private ValueTask DoTheDishes(ActivityExecutionContext context) => _dishCleaningService.DoDishesAsync(context.CancellationToken);
}

Observe que nesta versão do fluxo de trabalho, existem dois gatilhos baseados no tempo:

  1. Cron (que inicia o fluxo de trabalho sempre segunda-feira de manhã às 08:00)
  2. Temporizador (que começa a funcionar depois que o lixo foi limpo).

Implementá-lo com Quartz.NET exigiria que você agendasse manualmente um novo trabalho, possivelmente de algum manipulador de eventos levantado pelo serviço de limpeza. Factível, mas cada vez mais difícil de seguir à medida que a complexidade aumenta.

E é claro que seria muito triste para o cão ser caminhado apenas nas manhãs de segunda-feira. Felizmente Elsa torna mais fácil corrigir isso apenas declarando outra classe de fluxo de trabalho que cuida bem do cão.

Para saber mais sobre Elsa, confira o projeto no GitHub.

Resumo

Então aí está! Analisamos 3 opções viáveis de implementação de tarefas programadas em .NET Core/.NET 5.

A opção Serviço Hospedado é ótima para horários simples e recorrentes e não requer pacotes externos. Mas se você quer horários de cron, é melhor puxar as mangas e começar a escrever algum código.

Em seguida, olhamos para Quartz.NET, o que eu acho que é bastante incrível para implementar tarefas de fundo.

Finalmente, olhamos para Elsa Workflows, o que eu acho que é outra ótima escolha para tornar a implementação de tarefas de fundo uma brisa real. E sendo um fluxo de trabalho, ele automaticamente permite que você implemente fluxos de processos mais complexos e de longo prazo, onde você pode misturar e combinar qualquer tipo de gatilho além de eventos baseados no tempo. Exemplos incluem mensagens de ônibus de serviço, solicitações HTTP, eventos específicos de aplicativos e praticamente qualquer coisa que você possa sonhar.


Autor: Sipke Schoorstra

Artigo Original