Share via


Serviços de trabalho no .NET

Existem inúmeras razões para a criação de serviços de longa duração, tais como:

  • Processamento de dados com uso intensivo de CPU.
  • Enfileiramento de itens de trabalho em segundo plano.
  • Executar uma operação baseada no tempo em um cronograma.

O processamento de serviço em segundo plano geralmente não envolve uma interface do usuário (UI), mas as interfaces do usuário podem ser criadas em torno delas. Nos primórdios do .NET Framework, os desenvolvedores do Windows podiam criar os Serviços do Windows para esses fins. Agora, com o .NET, você pode usar o , que é uma implementação do IHostedService, ou implementar o BackgroundServiceseu próprio.

Com o .NET, você não está mais restrito ao Windows. Você pode desenvolver serviços em segundo plano entre plataformas. Os serviços hospedados estão prontos para registro, configuração e injeção de dependência (DI). Eles fazem parte do conjunto de extensões de bibliotecas, o que significa que são fundamentais para todas as cargas de trabalho do .NET que funcionam com o host genérico.

Importante

A instalação do SDK do .NET também instala o Microsoft.NET.Sdk.Worker modelo e o de trabalho. Em outras palavras, depois de instalar o SDK do .NET, você pode criar um novo trabalhador usando o comando dotnet new worker . Se você estiver usando o Visual Studio, o modelo ficará oculto até que a carga de trabalho opcional de ASP.NET e desenvolvimento da Web seja instalada.

Terminologia

Muitos termos são erroneamente usados como sinônimos. Esta seção define alguns desses termos para tornar sua intenção neste artigo mais aparente.

  • Serviço em segundo plano: O BackgroundService tipo.
  • Serviço Hospedado: Implementações de IHostedService, ou o IHostedService próprio.
  • Serviço de longa duração: qualquer serviço executado continuamente.
  • Serviço Windows: A infraestrutura de Serviço do Windows, originalmente centrada no .NET Framework, mas agora acessível via .NET.
  • Serviço do Trabalhador: O modelo do Serviço do Trabalhador.

Modelo de Serviço do Trabalhador

O modelo Worker Service está disponível na CLI do .NET e no Visual Studio. Para obter mais informações, consulte .NET CLI, dotnet new worker - template. O modelo consiste em uma Program classe e Worker .

using App.WorkerService;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();

IHost host = builder.Build();
host.Run();

A classe anterior Program :

  • Cria um HostApplicationBuilderarquivo .
  • Chamadas AddHostedService para registrar o Worker como um serviço hospedado.
  • Constrói um IHost a partir do construtor.
  • Chama Run a host instância, que executa o aplicativo.

Padrões de modelo

O modelo Worker não habilita a coleta de lixo do servidor (GC) por padrão, pois há vários fatores que desempenham um papel na determinação de sua necessidade. Todos os cenários que exigem serviços de longa execução devem considerar as implicações de desempenho desse padrão. Para habilitar o GC do servidor, adicione o ServerGarbageCollection nó ao arquivo de projeto:

<PropertyGroup>
    <ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>

Compensações e considerações

Ativados Disabled
Gerenciamento eficiente de memória: recupera automaticamente a memória não utilizada para evitar vazamentos de memória e otimizar o uso de recursos. Melhor desempenho em tempo real: evita possíveis pausas ou interrupções causadas pela coleta de lixo em aplicativos sensíveis à latência.
Estabilidade a longo prazo: Ajuda a manter um desempenho estável em serviços de longa duração, gerenciando a memória por longos períodos. Eficiência de recursos: pode conservar recursos de CPU e memória em ambientes com recursos limitados.
Manutenção reduzida: Minimiza a necessidade de gerenciamento manual de memória, simplificando a manutenção. Controle manual de memória: Fornece controle refinado sobre a memória para aplicações especializadas.
Comportamento previsível: contribui para um comportamento consistente e previsível do aplicativo. Adequado para processos de curta duração: Minimiza a sobrecarga da coleta de lixo para processos efêmeros ou de curta duração.

Para obter mais informações sobre considerações de desempenho, consulte GC do servidor. Para obter mais informações sobre como configurar o GC do servidor, consulte Exemplos de configuração do GC do servidor.

Classe operária

Quanto ao Worker, o modelo fornece uma implementação simples.

namespace App.WorkerService;

public sealed class Worker(ILogger<Worker> logger) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
            await Task.Delay(1_000, stoppingToken);
        }
    }
}

A classe anterior Worker é uma subclasse de BackgroundService, que implementa IHostedService. O BackgroundService é um abstract class e requer a subclasse para implementar BackgroundService.ExecuteAsync(CancellationToken). Na implementação do modelo, os ExecuteAsync loops uma vez por segundo, registrando a data e hora atuais até que o processo seja sinalizado para cancelar.

O arquivo de projeto

O modelo de trabalho depende do seguinte arquivo de Sdkprojeto:

<Project Sdk="Microsoft.NET.Sdk.Worker">

Para obter mais informações, consulte SDKs de projeto .NET.

Pacote NuGet

Um aplicativo baseado no modelo Worker usa o Microsoft.NET.Sdk.Worker SDK e tem uma referência explícita de pacote ao pacote Microsoft.Extensions.Hosting .

Contentores e adaptabilidade à nuvem

Com a maioria das cargas de trabalho .NET modernas, os contêineres são uma opção viável. Ao criar um serviço de longa execução a partir do modelo Worker no Visual Studio, você pode optar pelo suporte ao Docker. Isso cria um Dockerfile que conteineriza seu aplicativo .NET. Um Dockerfile é um conjunto de instruções para criar uma imagem. Para aplicativos .NET, o Dockerfile geralmente fica na raiz do diretório ao lado de um arquivo de solução.

# See https://aka.ms/containerfastmode to understand how Visual Studio uses this
# Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["background-service/App.WorkerService.csproj", "background-service/"]
RUN dotnet restore "background-service/App.WorkerService.csproj"
COPY . .
WORKDIR "/src/background-service"
RUN dotnet build "App.WorkerService.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "App.WorkerService.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "App.WorkerService.dll"]

As etapas anteriores do Dockerfile incluem:

  • Definindo a imagem base como mcr.microsoft.com/dotnet/runtime:8.0 o alias base.
  • Alterando o diretório de trabalho para /app.
  • Definindo o build alias da mcr.microsoft.com/dotnet/sdk:8.0 imagem.
  • Alterando o diretório de trabalho para /src.
  • Copiando o conteúdo e publicando o aplicativo .NET:
  • Retransmissão da imagem do SDK do .NET a partir de mcr.microsoft.com/dotnet/runtime:8.0 (o base alias).
  • Copiando a saída de compilação publicada do /publish.
  • Definindo o ponto de entrada, que delega ao dotnet App.BackgroundService.dll.

Gorjeta

O MCR em mcr.microsoft.com significa "Microsoft Container Registry", e é o catálogo de contêineres sindicados da Microsoft a partir do hub oficial do Docker. O artigo do catálogo de contêineres de sindicatos da Microsoft contém detalhes adicionais.

Quando você direciona o Docker como uma estratégia de implantação para seu .NET Worker Service, há algumas considerações no arquivo de projeto:

<Project Sdk="Microsoft.NET.Sdk.Worker">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>
    <RootNamespace>App.WorkerService</RootNamespace>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
  </ItemGroup>
</Project>

No arquivo de projeto anterior, o <DockerDefaultTargetOS> elemento especifica Linux como seu destino. Para direcionar contêineres do Windows, use Windows em vez disso. O Microsoft.VisualStudio.Azure.Containers.Tools.Targets pacote NuGet é adicionado automaticamente como uma referência de pacote quando o suporte ao Docker é selecionado no modelo.

Para obter mais informações sobre o Docker com .NET, consulte Tutorial: Containerize a .NET app. Para obter mais informações sobre como implantar no Azure, consulte Tutorial: Implantar um serviço de trabalho no Azure.

Importante

Se quiser aproveitar os Segredos de Usuário com o modelo de Trabalhador, será necessário fazer referência explícita ao Microsoft.Extensions.Configuration.UserSecrets pacote NuGet.

Extensibilidade do serviço hospedado

A IHostedService interface define dois métodos:

Esses dois métodos servem como métodos de ciclo de vida - eles são chamados durante os eventos de início e parada do host, respectivamente.

Nota

Ao substituir um ou StartAsyncStopAsync métodos, você deve chamar e await o base método de classe para garantir que o serviço seja iniciado e/ou desligado corretamente.

Importante

A interface serve como uma restrição de parâmetro de tipo genérico no método de extensão, o AddHostedService<THostedService>(IServiceCollection) que significa que apenas implementações são permitidas. Você é livre para usar o fornecido BackgroundService com uma subclasse, ou implementar o seu próprio completamente.

Conclusão do sinal

Na maioria dos cenários comuns, você não precisa sinalizar explicitamente a conclusão de um serviço hospedado. Quando o host inicia os serviços, eles são projetados para serem executados até que o host seja interrompido. Em alguns cenários, no entanto, talvez seja necessário sinalizar a conclusão de todo o aplicativo host quando o serviço for concluído. Para sinalizar a conclusão, considere a seguinte Worker classe:

namespace App.SignalCompletionService;

public sealed class Worker(
    IHostApplicationLifetime hostApplicationLifetime,
    ILogger<Worker> logger) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // TODO: implement single execution logic here.
        logger.LogInformation(
            "Worker running at: {Time}", DateTimeOffset.Now);

        await Task.Delay(1_000, stoppingToken);

        // When completed, the entire app host will stop.
        hostApplicationLifetime.StopApplication();
    }
}

No código anterior, o ExecuteAsync método não faz loop e, quando está concluído, chama IHostApplicationLifetime.StopApplication().

Importante

Isso sinalizará para o host que ele deve parar e, sem essa chamada para StopApplication o host, continuará a ser executado indefinidamente.

Para obter mais informações, consulte:

Consulte também