티스토리 뷰

프로젝트 중 사용자가 중복으로 등록되는 이슈로 인해 동시성 제어를 위해
@Retryable을 공부하다가 @Retryable과 @Transactional 의 주석 순서 차이로 인한 프로세스의 순서가 차이가 있음을 발견했습니다.

다음의 두 코드의 차이는 @Transactional@Retryable 어노테이션의 순서에 있습니다. 이 순서 차이로 인해 DataIntegrityViolationException 이 발생했을 때 프로세스에 미치는 영향은 다음과 같습니다.

  1. 첫 번째 코드:

    @Transactional
    @Retryable(
        retryFor = {DataIntegrityViolationException .class},
        maxAttempts = 1000,
        backoff = @Backoff(100)
    )
    public void insertUser(long ticketId) {}

    이 경우, @Transactional 어노테이션이 먼저 적용됩니다. 즉, insertUser 메서드가 트랜잭션 내에서 실행되고, 그 후에 @Retryable 어노테이션이 적용됩니다. 따라서 트랜잭션 내에서 DataIntegrityViolationException 이 발생하면 해당 트랜잭션이 롤백되고, @Retryable에 의해 메서드가 다시 시도됩니다. 재시도된 메서드는 새로운 트랜잭션에서 실행됩니다.

  2. 두 번째 코드:

    @Retryable(
        retryFor = {DataIntegrityViolationException .class},
        maxAttempts = 1000,
        backoff = @Backoff(100)
    )
    @Transactional
    public void insertUser(long ticketId) {}

    이 경우, @Retryable 어노테이션이 먼저 적용됩니다. 즉, insertUser 메서드는 트랜잭션 시작 전에 재시도 로직이 먼저 적용됩니다. 재시도 로직은 트랜잭션이 시작되기 전에 메서드를 재시도할 것입니다. 따라서, 재시도가 발생할 때마다 새로운 트랜잭션이 시작되고, 그 트랜잭션 내에서 메서드가 실행됩니다.

차이점 정리:

  • 첫 번째 코드: @Transactional이 먼저 적용되므로 메서드가 트랜잭션 내에서 실행되고, 실패할 경우 롤백 후 재시도합니다. 각 재시도는 새로운 트랜잭션에서 실행됩니다.
  • 두 번째 코드: @Retryable이 먼저 적용되므로 재시도 로직이 트랜잭션 시작 전에 적용됩니다. 따라서, 각 재시도는 트랜잭션을 시작하기 전에 이루어지며, 새로운 트랜잭션에서 메서드가 실행됩니다.

이로 인해 두 코드 간에 재시도 시점과 트랜잭션 경계에서의 차이가 발생합니다. 일반적으로 재시도 로직이 먼저 적용되는 두 번째 코드가 더 많이 사용되며, 이는 재시도 로직이 트랜잭션 관리와 독립적으로 작동하게 합니다.

결론

저의 케이스에서는 결론적으로 첫 번째 코드 를 적용하여 중복 시 익셉션을 발생시켜 우선 롤백을 하고 재시도할 수 있도록 적용하였습니다.