방프리

24.03.11 Chapter3. 태스크 기반 비동기 프로그래밍 (Item 33) 본문

C#/More Effective C#

24.03.11 Chapter3. 태스크 기반 비동기 프로그래밍 (Item 33)

방프리 2024. 3. 11. 23:01

Item 33 : 태스크 취소 프로토콜 구현을 고려하라

태스크 실행 도중에 문제가 생긴다면 메서드 호출 도중 취소 처리를 하는 방식도 고려해야 한다.
주로 CancellationToken을 활용하여 태스크 취소 처리를 진행한다.

public class ProgressReporter : 
    IProgress<(int percent, string message)>
{
    public void Report((int percent, string message) value)
    {
        WriteLine($"{value.Percent} completed: {value.message}"); 
    }
}

await generator.RunPayroll(DateTime.Now, new ProgressReporter());

public Task RunPayroll(DateTime payrollPeriod) =>
    RunPayRoll(payrollPeriod, new CancellationToken(), null);
    
public Task RunPayroll(DateTime payrollPeriod,
    CancellationToken cancellationToken) =>
        RunPayroll(payrollPeriod, cancellationToken, null);

public Task RunPayroll(DateTime payrollPeriod,
    IProgress(<int, string)> progress) =>
        RunPayroll(payrollPeriod, new CancellationToken(), progress);

public async Task RunPayroll(DateTime payrollPeriod,
    CancellationToken cancellationToken,
    IProgress<(int, string)> progress)
{
    progress?Report((0, "Starting Payroll"));
    
    // Step 1. 근무 시간과 급여계산
    var payrollData = await RetrieveEmployeePayrollDataFor(payrollPeriod);
    cancellationToken.ThrowIfCancellationRequested();
    progress?.Report((20, "Retrieved employees and hours"));
    
    // Step 2. 세금 계산 및 신고
    var taxReporting = new Dictionary<EmployeePayrollData, TaxWithholding>();
    foreach (var employee in payrollData)
    {
        var taxWithholding = await RetrieveTaxData(employee);
        taxReporting.Add(employee, taxWithholding);
    }
    cancellationToken.ThrowIfcancellationRequested();
    progress?.Report((40, "Calculated Withholding"));
    
    // Step 3. 급여 명세서 생성 및 이메일 전송
    var paystubs = new List<Task>();
    foreach (var payrollItem in taxReporting)
    {
        var payrollTask = GeneratePayrollDocument(
            payrollItem.Key, payrollItem.Value);
        var emailTask = payrollTask.ContinueWith(
            paystub => EmailPaystub(payrollItem.Key.Email, paystub.Result));
        paystubs.Add(emailTask);
    }
    
    await Task.WhenAll(paystubs);
    cancellationToken.ThrowIfCancellationRequested();
    progress?Report((60, "Emailed Paystubs"));
    
    // Step 4. 급여송금
    var depositTasks = new List<Task>();
    foreach (var payrollItem in taxReporting)
    {
        depositTasks.Add(MakeDeposit(payrollItem.Key, payrollItem.Value));
    }
    
    await Task.WhenAll(depositTasks);
    progress?.Report((80, "Deposited pay"));
    
    // Step 5. 급여 지급 기간 마감
    await ClosePayrollPeriod(payrollPeriod);
    cancellationToken.ThrowIfCancellationRequested();
    progress?.Report((100, "complete"));
}
Comments