본문 바로가기
프로그래밍/C#

계속 실행되어야 하는 작업을 위한 BackgroundService in .NET Core

by bantomak 2023. 6. 5.

IHostedService

.NET Core 2.1에서 추가된 IHostedService은 개발자에게 관리되는 실행시간에서 백그라운드 서비스들을 실행할 수 있도록 해준다.

 

이 기능은 최소한의 구현만을 사용이 가능합니다.

public interface IHostedService
{
    Task StartAsync(CancellationToken cancellationToken);
    Task StopAsync(CancellationToken cancellationToken);
}

 

.NET Core의 의존성 주입을 해줍니다. 간단하게 구현이 가능하다!

 

var hostBuilder = new HostBuilder()
  .ConfigureServices(services =>
     services.AddHostedService<WorkerService>());

 

실사용 예

IHostedService를 사용한 일반적인 사용 패턴을 살펴보면

  • 시간제한 백그라운드 작업
  • 범위가 정해진 서비스 처리
  • 백그라운드 큐

 

IHostedService를 통해서 아래와 같은 장기 실행되는 백그라운드 서비스를 등록하려고 했지만

public override async Task StartAsync(CancellationToken cancellationToken)
{
    while (!cancellationToken.IsCancellationRequested)
    {
      //Do Something
    }
}

위와 같은 구현은 서비스를 멈추고 나머지 모든 것을 정지시킬 것이다. 처음에는 IHostedService가 알아서 백그라운드로 실행돼서 StartAsync 함수에 등록하기만 하면 잘 작동될 거라고 예상했는데 아니었다.

 

IHostedService는 단기로 실행되는 백그라운드 실행으로 제한되어 있다.

 

BackgroundService

지속적으로 실행되야하는 작업을 위해서 IHostedService를 상속받는 BackgroundService를 구현할 필요가 있다.

해당 타입의 ExecuteAsync 메서드를 Override 해준다.

 

public class WorkerHostedService : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stopToken)
    {
      //Do your preparation (e.g. Start code) here
      while (!stopToken.IsCancellationRequested)
      {
        await DoSomethingAsync();
      }
      //Do your cleanup (e.g. Stop code) here
    }
}

 

result
이제 백그라운드에서 실행되는걸 확인했다.

(해당 메시지가 뜨지 않았다면 애플리케이션이 블록 되었다는 뜻이다. 코드를 다시 살펴보도록 하자.)

 

아래 코드에서 보듯 BackgroundService를 실제로 루프를 돌리기 위해서 다른 작업을 생성한다.

 

public abstract class BackgroundService : IHostedService, IDisposable
{
    private Task _executingTask;
    private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();
    
    protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
    
    public virtual Task StartAsync(CancellationToken cancellationToken)
    {
        // Store the task we're executing
        _executingTask = ExecuteAsync(_stoppingCts.Token);
        
        // If the task is completed then return it, this will bubble cancellation and failure to the caller
        if (_executingTask.IsCompleted)
        {
            return _executingTask;
        }
        
        // Otherwise it's running
        return Task.CompletedTask;
    }
    
    public virtual async Task StopAsync(CancellationToken cancellationToken)
    {
        // Stop called without start
        if (_executingTask == null)
        {
            return;
        }
        try
        {
            // Signal cancellation to the executing method
            _stoppingCts.Cancel();
        }
        finally
        {
            // Wait until the task completes or the stop token triggers
            await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
        }
    }
    
    public virtual void Dispose()
    {
        _stoppingCts.Cancel();
    }
}

 

 

Reference

 

BackgroundService in .NET Core for long running tasks

.NET Core 2.1 has a new feature called IHostedService to allow developers to run a background service that can have a managed lifetime to…

medium.com

댓글