[Akka] 예외 처리

smlee·2023년 9월 6일
0

Akka

목록 보기
16/50
post-thumbnail

Scala에서는 Try- match로 예외처리를 하며, Java에서는 try-catch문으로 예외 처리를 한다.

이러한 예외 처리 코드들은 예외가 발생한 소스로부터 멀리 떨어져있으므로 예외가 발생한 이유를 알기 어렵고 어떻게 처리하는지는 더더욱 알기 힘들다.

따라서 액터 모델은 이러한 문제점을 해결하기 위해 "고장나도록 허용"하는 원칙을 내세운다. 즉, 자바나 스칼라처럼 오류처리 블록을 따로 두지 않고 내버려두는 전략이다.

그렇다고 예외를 처리하지 않는것이 아니라, 어느 액터가 발생시킨 예외는 그 액터의 감시자(supervisor)가 처리하도록 하는 것이다.

다음 2가지 예제를 보자.

import akka.actor {ActorSystem, Props}
import resource.actor.PingActor

object GoodMain {
	def main(args: Array[String]) = {
    val actorSystem = ActorSystem.create("TestSystem")
    val ping = actorSystem.actorOf(Props.create(classOf[PingActor]))
    ping ! "good"
  }
}
import akka.actor.{ActorSystem, Props}
import resource.actor.PingActor

object BadMain {
  def main(args: Array[String]) = {
    val actorSystem = ActorSystem.create("TestSystem")
    val ping = actorSystem.actorOf(Props.create(classOf[PingActor]))
    ping ! "bad"
  }
}

위의 2개의 코드에서는 각각 ping이라는 actor에 "good"이라는 메시지와 "bad"라는 메시지를 보내는 클래스이다.

import akka.actor.{Actor, Props}
import akka.event.Logging

/**
  * "good"이나 "bad" 메시지를 받으면 Ping1Actor라는 자식 액터에게 전달.
  * "done" 메시지를 받으면 화면에 결과를 출력.
  */
class PingActor extends Actor {
  val log = Logging(context.system, this)
  val child = context.actorOf(Props.create(classOf[Ping1Actor]), "ping1Actor")

  def receive = {
    case msg@"good" => child ! msg
    case msg@"bad" => child ! msg
    case msg@"done" => log.info("a task is successfully completed.")
  }
}

위는 핑 액터이며, 만약 올바르지 않은 메시지가 들어오기 위해서는 다음과 같이 처리한다.

import akka.actor.SupervisorStrategy.{Escalate, Restart, Resume, Stop}
import akka.actor.{Actor, OneForOneStrategy, Props}
import akka.event.Logging
import scala.concurrent.duration._

/**
  * 자식 액터들을 감시하기 위한 전략을 선언하는 액터
  */
class Ping1Actor extends Actor {
  val log = Logging(context.system, this)
  val child1 = context.actorOf(Props.create(classOf[Ping2Actor]), "ping2Actor")
  val child2 = context.actorOf(Props.create(classOf[Ping3Actor]), "ping3Actor")

  def receive = {
    case msg : String  =>
      log.info(s"Ping1Actor received $msg")
      child1.tell(msg, sender)
      child2.tell(msg, sender)
  }

  override val supervisorStrategy =
    OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
      case _: ArithmeticException => Resume  
      case _: NullPointerException => Restart 
      case _: IllegalArgumentException => Stop
      case _ => Escalate

    }
}

위의 예시 코드는 감시 전략에 예외 처리를 감싼 것이다. 이제 위의 액터의 자식 액터들까지 적용되는 감시 전략이 된다.

import akka.actor.Actor
import akka.event.Logging

class Ping2Actor extends Actor {
  val log = Logging(context.system, this)

  override def preRestart(reason: Throwable, message: Option[Any]) = {
    log.info("Ping2Actor preRestart..")
  }

  override def postRestart(reason: Throwable) = {
    log.info("Ping2Actor postRestart..")
  }

  override def postStop = {
    log.info("Ping2Actor postStop..")
  }

  override def receive = {
    case msg@"good" =>
      goodWork
      sender ! "done"
    case msg@"bad" =>
      badWork
  }

  private def goodWork = log.info("Ping2Actor is good.")
  private def badWork = { val a = 1 / 0 } /** 일부러 ArithmeticException을 발생시킨다 */
}

일부러 NullPointerException과 ArithmeticException를 발생하기 위한 메시지를 생성하기 위한 메서드를 선언하였고, 메시지에 따라 어떤 오류를 발생시키는 메시지를 주었다.

import akka.actor.Actor
import akka.event.Logging

class Ping3Actor extends Actor {
  val log = Logging(context.system, this)

  override def preRestart(reason: Throwable, message: Option[Any]) = {
    log.info("Ping3Actor preRestart..")
  }

  override def postRestart(reason: Throwable) = {
    log.info("Ping3Actor postRestart..")
  }

  override def postStop = {
    log.info("Ping3Actor postStop..")
  }

  override def receive = {
    case msg@"good" =>
      goodWork
      sender ! "done"
    case msg@"bad" =>
      badWork
  }

  private def goodWork = log.info("Ping3Actor is good.")
  private def badWork = { throw new NullPointerException } /** 일부러 NullPointerException을 발생시킨다 */
}

또한 위의 액터 역시 일부러 오류를 발생시켰다.



위와 같이 감시전략에서 선언한 오류가 잘 출력되는 것을 알 수 있다. 위의 Resume이나 Restart와 같은 것들은 Akka Actor의 Lifecycle 관련 게시물에 정리해놨으므로 이를 참고한다.

0개의 댓글