Background Service | CSharp
- Background Service | CSharp
Background Services são serviços ou tarefas executadas continuamente ou periodicamente em segundo plano em aplicações .NET.
BackgroundService NÃO cria um novo processo. Ele roda no mesmo processo da aplicação. Roda esse código em uma Task assíncrona. Tudo acontece dentro do mesmo processo (PID) da aplicação.
Breve explicação sobre Processo x Thread x Task
Processo
- Isolamento total
- Memória própria
- Criado pelo sistema operacional
Thread
- Executa dentro do mesmo processo
- Compartilha memória
- Criada pelo runtime
Task
- Abstração de execução assíncrona
- Usa thread pool
- Não cria thread dedicada por padrão
👉 BackgroundService usa Task + ThreadPool, não processo novo.
BackgroundService contínuo** | Work
Ideal para serviços que rodam continuamente, como workers que escutam filas.
public class ContinuousWorker : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
Console.WriteLine("Executando tarefa contínua...");
await Task.Delay(5000, stoppingToken);
}
}
}
Serviço com Timer (Tarefa Recorrente)
Usado para executar uma tarefa de tempos em tempos, sem bloquear o thread.
public class TimedWorker : BackgroundService
{
private Timer? _timer;
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(10));
return Task.CompletedTask;
}
private void DoWork(object? state)
{
Console.WriteLine($"Executando tarefa periódica: {DateTime.Now}");
}
public override Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Change(Timeout.Infinite, 0);
return base.StopAsync(cancellationToken);
}
}
Queue-based com Channel<T>
Para tarefas assíncronas enfileiradas, muito usado em APIs que delegam trabalho pesado para o background.
public class ChannelQueueWorker : BackgroundService
{
private readonly Channel<string> _queue;
public ChannelQueueWorker(Channel<string> queue)
{
_queue = queue;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await foreach (var item in _queue.Reader.ReadAllAsync(stoppingToken))
{
Console.WriteLine($"Processando item da fila: {item}");
await Task.Delay(1000); // Simula trabalho
}
}
}
// Para uso com injeção
builder.Services.AddSingleton(Channel.CreateUnbounded<string>());
builder.Services.AddHostedService<ChannelQueueWorker>();
Scoped BackgroundService
Usado quando você precisa de dependências com escopo (
Scoped), como umDbContext.
public class ScopedWorker : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
public ScopedWorker(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _serviceProvider.CreateScope())
{
var myService = scope.ServiceProvider.GetRequiredService<IMeuServico>();
await myService.ProcessarAsync();
}
await Task.Delay(10000, stoppingToken);
}
}
}
Agendador com Hangfire
Ideal para agendar tarefas com recorrência mais complexa, como cron jobs.
public class HangfireTasks
{
public static void ExecutarTarefa()
{
Console.WriteLine("Tarefa agendada executada com Hangfire.");
}
}
// Configuração em Startup ou Program.cs
RecurringJob.AddOrUpdate("tarefa-diaria", () => HangfireTasks.ExecutarTarefa(), Cron.Daily);
Hangfire roda com
BackgroundJobServerque processa em paralelo, sem necessidade deBackgroundService.
Agendador com Quartz.NET
Quando você precisa de tarefas agendadas com controle fino (prioridades, dependências, etc).
public class QuartzJob : IJob
{
public Task Execute(IJobExecutionContext context)
{
Console.WriteLine("Tarefa Quartz executada.");
return Task.CompletedTask;
}
}
// Configuração
builder.Services.AddQuartz(q =>
{
var jobKey = new JobKey("job1");
q.AddJob<QuartzJob>(opts => opts.WithIdentity(jobKey));
q.AddTrigger(opts => opts
.ForJob(jobKey)
.WithIdentity("trigger1")
.WithCronSchedule("0/30 * * * * ?")); // A cada 30 segundos
});
builder.Services.AddQuartzHostedService();
Implementação direta com IHostedService
Permite total controle sobre o ciclo de vida.
public class CustomHostedService : IHostedService
{
private Task? _executingTask;
private CancellationTokenSource? _cts;
public Task StartAsync(CancellationToken cancellationToken)
{
_cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
_executingTask = Task.Run(() => DoWork(_cts.Token), cancellationToken);
return Task.CompletedTask;
}
private async Task DoWork(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
Console.WriteLine("Executando serviço customizado...");
await Task.Delay(3000, token);
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
_cts?.Cancel();
return Task.CompletedTask;
}
}
lus
Cada tipo de BackgroundService ou tarefa em segundo plano no .NET atende a um propósito diferente:
| Tipo | Melhor uso |
|---|---|
BackgroundService | Processos contínuos |
| Timer | Tarefas recorrentes simples |
Channel<T> | Fila de tarefas internas |
| Scoped | Operações que usam serviços scoped como DbContext |
| Hangfire / Quartz | Agendamentos complexos ou cron |
IHostedService direto | Controle total e customização |