본문 바로가기
Spring

[Spring] @TransactionalEventListener

by 에드박 2021. 8. 25.

자신이 작성한 오브젝트(피드, 댓글)에 다른 유저가 상호작용(좋아요, 댓글, 대댓글)을 하면 알림주는 기능을 구현했습니다.

알림은 오브젝트들과 강한 결합을 만들기는 적절하지 않다고 생각해서 EventListener를 사용하면 어떨까? 생각했습니다.

EventListener를 이용해서 특정 시점(좋아요 저장, 댓글 저장, 대댓글 저장)에 알림을 저장하는 이벤트를 실행시켰습니다.

이때 신경썼던 포인트는 다음과 같습니다.

  • 상호작용(좋아요, 댓글, 대댓글)을 저장할때 알림이 저장에 실패한다고 상호작용도 함께 롤백되서는 안됩니다.(알림은 저장에 실패해도 상호작용은 정상적으로 저장되야함)
  • 상호작용 저장에 실패하면 알림도 저장되어선 안됩니다.

위 두가지 요구사항을 충족하기 위해 사용한 EventListener는
@TransactionalEventListener 입니다.
기본적인 @EventListener와 차이점이 있습니다.

@TransactionalEventListener는 이벤트를 호출한 곳의 트랙잭션을 기준으로 이벤트를 발행합니다. 그 시점은 4가지가 있습니다.

  • AFTER_COMMIT(default) - default 설정입니다. 트랜잭션의 커밋이 발생한 이후 이벤트를 발행합니다.
  • AFTER_ROLLBACK - 롤백이 발생한 이후 이벤트를 발행합니다.
  • AFTER_COMPLETION - 트랜잭션이 완료된 후 이벤트를 발행합니다.
  • BEFORE_COMMIT - 커밋 직전에 이벤트를 발행합니다.

알림 기능에 사용한 설정은 AFTER_COMMIT 입니다.
커밋까지 된 후에 이벤트를 발행하면 아래의 경우가 가능했습니다.

  • 상호작용 저장에 실패하면 rollback이 일어나므로 이벤트 발행을 하지않음(상호작용 저장 X -> 알림 저장 이벤트 발행 X)
  • 상호작용 저장이 성공하고 이벤트를 발행하기 때문에 알림의 저장 성공 여부는 상호작용 저장에 영향이 없습니다

한 가지 문제가 발생했던것은 AFTER_COMMIT 설정을 사용했더니 트랜잭션은 커밋이 된 상태이지만 트랜잭션이 완료된 상태는 아니었기때문에 이벤트 발행이후 같은 트랜잭션에서 진행이 되어 트랜잭션을 이용할 수 없는 이슈가 있었습니다.
따라서 알림을 저장하는 메소드에는 @Transactional(propagation = Propagation.REQUIRES_NEW) 를 사용하여 항상 새로운 트랜잭션을 시작하도록 설정했습니다.

댓글