Em nosso mais recente projeto, enfrentamos o desafio de gerenciar múltiplos processos assíncronos de forma resiliente com escalabilidade. Entre esses processos estavam fluxos de pré-agendamento, monitoramento de NFe integrado a serviços externos e rotinas automatizadas de No-Show, responsáveis por identificar e tratar situações de não comparecimento de forma automática
Para centralizar e garantir a execução dessas tarefas, implementamos o Hangfire integrado ao ciclo de vida da aplicação via IHostedService.
Mas o que seria o Hangfire? Hangfire é biblioteca de código aberto para o ecossistema .NET, projetada para facilitar a criação, processamento e gerenciamento de tarefas em segundo plano (background) de formar resiliente e assíncronos.
Desacoplamento e Injeção de Dependência:
Criamos um método de extensão corporativo AddBackgroundJobs para estender a IServiceCollection. Isso mantém a classe Program.cs (Startup) limpa, legível e aderente ao princípio de responsabilidade única.
public static IServiceCollection AddBackgroundJobs(this IServiceCollection services)
{
// Registra os recorrentes de Scheduling no startup da aplicacao.
services.AddHostedService();
// Job de sincronizacao NFe de entrada legado.
services.AddHostedService();
return services;
}
Trecho d configuração no Program.cs.
# region Job Hangfire
builder.Services.AddBackgroundJobs();
#endregion
Ciclo de Vida Controlado via Hosted Service:
Utilizamos o SchedulingRecurringJobsHostedService derivado de IHostedService. O registro das rotinas cron (RecurringJob.AddOrUpdate) acontece estritamente no método StartAsync, garantindo que os agendamentos sejam atualizados no storage assim que a aplicação é inicializada pelo servidor.
public sealed class SchedulingRecurringJobsHostedService(ILogger logger) : IHostedService
{
private readonly ILogger _logger = logger;
public Task StartAsync(CancellationToken cancellationToken)
{
var timeZone = TimeZoneInfo.FindSystemTimeZoneById(
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? "E. South America Standard Time"
: "America/Sao_Paulo");
// Mantem os mesmos IDs historicos para atualizar registros existentes no storage.
RecurringJob.AddOrUpdate(
"WorkflowPreAgendamen",
job => job.RunPreScheduleWorkflowAsync(),
"7 5 * * 1-5",
new RecurringJobOptions
{
TimeZone = timeZone
});
_logger.LogInformation("Recurring jobs de scheduling registrados no Hangfire.");
return Task.CompletedTask;
}
}
Compatibilidade Cross-Platform (Windows vs. Linux/Docker):
Um dos maiores gargalos em agendamentos globais é a divergência de fusos horários entre ambientes de desenvolvimento e produção. Resolvemos isso dinamicamente avaliando a plataforma em tempo de execução:
- Se Windows: “E. South America Standard Time”
- Se Linux (Containers): “America/Sao_Paulo”
Dessa forma, garantimos a execução precisa dos gatilhos nos horários de Brasília, independente da infraestrutura de hospedagem.
var timeZone = TimeZoneInfo.FindSystemTimeZoneById(
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? "E. South America Standard Time"
: "America/Sao_Paulo");
Preservação de Histórico de Execução:
Mantivemos identificadores fixos e explícitos para cada job (como “WorkflowPreAgendamen”, “MoniturarNFeJob” e “JobNoShow”). Isso evita a duplicação de tarefas no banco de dados e preserva as métricas históricas de auditoria no dashboard do Hangfire.


