728x90
반응형
https://data-gardner.tistory.com/171
간단한 콘솔 앱을 만들어보았다.
Worker의 background에서 event가 channel에 쌓일 때마다 IMyService를 통해 event를 처리한다.
IMyService가 event를 처리하는데 소요되는 시간은 event가 발생하는 주기보다 길다.
event가 channel에 계속 쌓여가는 상태에서 시스템이 종료되면 이미 쌓인 event는 MyService가 처리하지 못하므로,
MyService가 모든 event를 처리할 때까지 system은 종료하지 않도록 한다.
핵심은 appLifetime.ApplicationStopping과 appLifetime.ApplicationStopped를 잘 활용하는 것이다.
Stopping은 종료 프로세스가 시작되기 전, Stopped는 애플리케이션이 종료된 후 이벤트 처리기를 트리거한다.
*참고
- Program.cs
using GracefulShutdown;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddSingleton<IMyService, MyService>()
.AddSingleton<Worker>()
.AddHostedService(p => p.GetRequiredService<Worker>());
var app = builder.Build();
app.Run();
- MyService.cs
namespace GracefulShutdown
{
public class MyService : IMyService
{
public void DoSomething(int num)
{
Console.WriteLine("---------DO {0}", num);
Thread.Sleep(500);
}
}
}
- Worker.cs
using System.Threading.Channels;
namespace GracefulShutdown
{
public class Worker : BackgroundService
{
private readonly IMyService _myService;
private readonly Channel<object> _eventChannel = Channel.CreateUnbounded<object>();
private int _num;
public Worker(
IMyService myService,
IHostApplicationLifetime appLifetime)
{
_myService = myService;
appLifetime.ApplicationStopping.Register(() => Console.WriteLine("Stopping"));
appLifetime.ApplicationStopped.Register(() => ExecuteTask?.Wait(Timeout.InfiniteTimeSpan));
}
public void WriteRequestAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
Console.WriteLine("Requested : {0}", _num);
_eventChannel.Writer.WriteAsync(_num++, cancellationToken);
Thread.Sleep(300);
}
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_ = Task.Run(() => WriteRequestAsync(stoppingToken));
await foreach (var a in _eventChannel.Reader.ReadAllAsync(stoppingToken))
{
HandleDo((int)a);
}
}
private void HandleDo(int num)
{
_myService.DoSomething(num);
}
}
}
Channel의 경우, cancellationToken이 IsCanceled임에도 event가 쌓여 있으면 라이브러리 내에서 토큰을 전달하지 않는다.
따라서, ApplicatonStopped로 event 처리를 완료할 때까지 대기한 뒤,
channel 내에 event가 없어 cancel 토큰이 라이브러리 내부로 전달되어 Task가 완료되면
앱을 종료한다.
728x90
반응형
'Programming > .Net(C#)' 카테고리의 다른 글
다형성 유형 직렬화(Serialize Polymorphic Types) (0) | 2024.06.27 |
---|---|
입출력과 변수 (0) | 2021.05.10 |