Skip to main content

Background Service | CSharp

  • Background Service | CSharp

info

Background Services são serviços ou tarefas executadas continuamente ou periodicamente em segundo plano em aplicações .NET.

danger

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 um DbContext.

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 BackgroundJobServer que processa em paralelo, sem necessidade de BackgroundService.


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:

TipoMelhor uso
BackgroundServiceProcessos contínuos
TimerTarefas recorrentes simples
Channel<T>Fila de tarefas internas
ScopedOperações que usam serviços scoped como DbContext
Hangfire / QuartzAgendamentos complexos ou cron
IHostedService diretoControle total e customização