Entity Framework Core에서 `CreateExecutionStrategy()`의 사용

Entity Framework Core에서 `CreateExecutionStrategy()`는 **실행 전략(Execution Strategy)**을 创建하는 데 사용됩니다. 이 기능의 주된 목적은 데이터베이스 작업 중에서 발생하는 **일시적인 오류(Transient Failures)**를 처리하는 것입니다. 예를 들어 네트워크 플러그, 데이터베이스 연결 중단, 데드락과 같은 순간적인 오류가 있을 때 이 기제가 중요한 역할을 합니다. 특히 클라우드 환경(예: Azure SQL)이나 고并发 상황에서 이 기능은 애플리케이션의 **오류ทน성(Tolerance)**과 **튼튼함(Robustness)**을 크게 향상시킵니다.

실행 전략의 역할

실행 전략은 다음과 같이 작동합니다:

  • **자동 재시도(Automatic Retries)**: 일시적인 오류가 발생할 때(예: `SqlException` 및 오류 코드가 일시적인 오류를 나타내는 경우) 작업을 자동으로 재시도합니다.
  • **트랜잭션 일관성(Transaction Consistency)**: 재시도 과정에서 트랜잭션의 완전성과 일관성을 보장하여 부분 커밋을 방지합니다.
  • **유연한 구성(Flexible Configuration)**: 재시도 횟수, 재시도 간격 및 예외 필터링 조건을 맞춤형으로 설정할 수 있습니다.

예를 들어 SQL Server의 기본 실행 전략(`SqlServerRetryingExecutionStrategy`)은 특정 일시적인 오류(예: 오류 번호 `40613`, `40197`)에 대해 자동으로 재시도합니다.

트랜잭션 코드에서 실행 전략이 왜필요한가?

트랜잭션 작업 중에 데이터베이스 연결이 일시적인 오류로 중단될 수 있습니다. 이 경우 단순한 트랜잭션 코드(예: `BeginTransaction` 및 `Commit`)만 사용하면 전체 작업이 회복 불가능하게 중단될 수 있습니다. 실행 전략은 트랜잭션 처리를 다음과 같이 최적화합니다:

사례 예시

아래 코드가 실행 전략 없이 트랜잭션을 처리하는 예입니다:

using var transaction = await _dbContext.BeginTransactionAsync();
try
{
    // 작업 1: 주문 상태 업데이트
    await _dbContext.SaveChangesAsync();

    // 작업 2: 재고 차감
    await _dbContext.SaveChangesAsync();

    await transaction.CommitAsync();
}
catch (Exception ex)
{
    await transaction.RollbackAsync();
    throw;
}

문제: 작업 2가 일시적인 오류로 인해 실패하면 전체 트랜잭션이롤백됩니다. 사용자는 작업을 수동으로 다시 시작해야 합니다.

해결: 트랜잭션 코드를 실행 전략으로 감싸면 자동으로 작업을 재시도합니다.

실행 전략과 트랜잭션의 협업

제공된 코드 중:

var strategy = _dbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
    using (var transaction = await _dbContext.BeginTransaction())
    {
        await next(); // 비즈니스 작업 실행(여러번의 SaveChanges 포함할 수 있음)

        await _dbContext.CommitTransaction(transaction);
    }
});

중요한 점:

  1. 트랜잭션 트랜잭션 전략에 포함: 실행 전략은 트랜잭션 블록(`BeginTransaction` → 비즈니스 작업 → `Commit`)을 일시적인 오류로 인해 실패할 때 자동으로 재시도합니다.
  2. 재시도의 원자성: 각 재시도는 새 트랜잭션을 생성하며, 각 시도는 독립적이므로 잔존 상태를 피합니다.
  3. 농leichbedingung(幂等성): 비즈니스 작업은 재시도시 중복 부작용을 유발하지 않아야 합니다. 예를 들어 고유 제약이나 평등 토큰을 통해 중복 작업을 방지할 수 있습니다.

실행 전략의 대표적인 구성

Entity Framework Core에서 실행 전략은 보통 `DbContextOptionsBuilder`를 통해 구성됩니다:

services.AddDbContext<MyDbContext>(options =>
    options.UseSqlServer(
        connectionString,
        options => options.EnableRetryOnFailure(
            maxRetryCount: 5,
            maxRetryDelay: TimeSpan.FromSeconds(30),
            errorNumbersToAdd: null
        )
    )
);

설명:

  • EnableRetryOnFailure: SQL Server의 기본값 재시도 전략을 사용합니다.
  • maxRetryCount: 최대 재시도 횟수.
  • maxRetryDelay: 재시도 간의 최대 지연 시간.

코드 중에서 왜 명시적으로 `CreateExecutionStrategy()`를 호출해야 하나요?

기본적으로 실행 전략은 `EnableRetryOnFailure`를 통해 이미 활성화되어 있지만, 다음 상황에서 명시적으로 `CreateExecutionStrategy()`를 호출해야 합니다:

  • **명시적인 트랜잭션 경계 필요 시**: 비즈니스 로직이 여러 번의 `SaveChanges`를 포함하거나 EF와 비-EF 작업을 혼합할 때 트랜잭션 경계를 명시적으로 제어할 필요가 있을 때.
  • **수동적으로 재시도 로직 트IGGER링 시**: 예를 들어 MediatR 파ipeline Behavior에서 트랜잭션 및 재시도 로직을 통합적으로 관리할 때(예제 코드 참조).

실행 전략의 주의사항

  • 트랜잭션 영역(Transaction Scope): 실행 전략은 전체 트랜잭션을(즉 `BeginTransaction` 및 `Commit`을 포함) 반드시 포함해야 합니다. 그렇지 않으면 재시도할 때 트랜잭션이 재설정되지 않아 실패할 수 있습니다.
  • 부작용 방지: 트랜잭션 안의 작업은 평등해야 합니다. 즉, 재시도시 중복 부작용을 유발해서는 안 됩니다(예: 이메일 보내기, 외부 API 호출).
  • 컨텍스트 상태(Context State): 재시도시 `DbContext`의 추적 엔티티 상태가 재설정됩니다. 따라서 각 재시도 작업은 완전해야 합니다(예: 데이터를 다시 로드해야 할 수 있습니다).

요약

제공된 코드에서 `CreateExecutionStrategy()`의 역할은:

  • 오류 보호: 일시적인 오류로 인해 실패한 트랜잭션 작업을 자동으로 재시도합니다.
  • 트랜잭션 완전성: 재시도할 때 트랜잭션 블록의 원자성을 유지합니다.
  • 통합 관리: MediatR 파ipeline에서 트랜잭션 및 재시도 로직을 단일로 관리하여 코드의 유지 보수성을 향상시킵니다.

만약 실행 전략을 사용하지 않으면 일시적인 오류로 인해 트랜잭션이 즉시 실패하고 클라이언트가 수동으로 작업을 다시 시작해야 합니다. 이는 시스템의 신뢰성을 저하시킬 수 있습니다.

태그: Entity Framework Core Execution Strategy Transaction Handling

8월 1일 02:12에 게시됨