Microsoft .NET/ASP.Net & ASP.Net Core
[.NET] BackgroundService로 주기 작업 만들기, 종료 처리까지
전자기린
2026. 11. 10. 00:45

ASP.NET Core에서 주기적으로 도는 작업(정리, 동기화, 알림)을 만드는 가장 단순한 방법인 BackgroundService 정리입니다.
절차
- 최소 구현
- DI 주입 주의
- 정상 종료 처리
- 운영에서 확인할 것
1. 최소 구현
public class CleanupWorker : BackgroundService
{
private readonly ILogger<CleanupWorker> _logger;
public CleanupWorker(ILogger<CleanupWorker> logger) => _logger = logger;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("정리 작업 실행 {Time}", DateTimeOffset.Now);
await Task.Delay(TimeSpan.FromMinutes(10), stoppingToken);
}
}
}builder.Services.AddHostedService<CleanupWorker>();ExecuteAsync가 반환되면 작업이 끝난 것으로 보므로, 반복은 while로 직접 돌립니다.
2. DI 주입 주의
BackgroundService는 Singleton입니다. AppDbContext 같은 Scoped 서비스를 생성자로 받으면 시작할 때 예외가 납니다.
using var scope = _scopeFactory.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();3. 정상 종료 처리
앱이 내려갈 때 stoppingToken이 취소됩니다. 모든 await에 토큰을 넘기고, 오래 걸리는 루프는 중간에 취소를 확인합니다.
foreach (var item in items)
{
stoppingToken.ThrowIfCancellationRequested();
await ProcessAsync(item, stoppingToken);
}종료 대기 시간은 기본 5초입니다. 더 필요하면 호스트 옵션으로 늘립니다.
builder.Services.Configure<HostOptions>(o =>
o.ShutdownTimeout = TimeSpan.FromSeconds(30));4. 운영에서 확인할 것
- 인스턴스를 여러 개 띄우면 같은 작업이 중복 실행됩니다 — 분산 락이나 별도 워커로 분리
- IIS 뒤에서는 앱 풀 재활용으로 프로세스가 내려갑니다 — 계속 돌려야 하면 Windows 서비스나 systemd로 등록
- 실행 로그를 남겨 실제로 도는지 확인
정리
ExecuteAsync안에서 while 루프- Scoped 의존성은
IServiceScopeFactory로 - 종료 토큰을 모든 await에 전달