일정 시간마다 균일하게 특정 작업을 실행하고 싶은 경우가 있을 것이다. 이런 경우 Scheduler
와 Timer
를 사용하여 일정한 기간 동안 반복하여 실행할 수 있다.
스케줄러는 system.scheduler
로 접근하여 사용할 수 있다.
scheduleOnce(delayPeriod)
는 deplayPeriod
후에 한 번만 실행하는 것을 뜻한다. 밑의 예시 코드를 한 번 보자.
import scala.concurrent.duration._
val system = ActorSystem("timerSystem)
val simpleActor = system.actorOf(Props[SimpleActor], "simpleActor")
system.scheduler.scheduleOnce(1 second) {
simpleActor ! InitialMessage
} (system.dispatcher)
위의 코드는 1초 뒤
에 SimpleActor에게 InitialMessage를 보내는 코드이다. 이때, delayPeriod를 설정하기 위해 scala.concurrent.duration._
을 임포트시켜야 한다. 그리고 중괄호 안에 실행할 동작을 선언한 다음 dispatcher를 넣어주어야 한다.
system.dispatcher
는 execution context interface를 구현한 것으로, implicit
로 선언하면 굳이 뒤에 쓸 필요가 없다.
import scala.concurrent.duration._
val system = ActorSystem("timerSystem)
val simpleActor = system.actorOf(Props[SimpleActor], "simpleActor")
implicit val executionContext = system.dispatcher
system.scheduler.scheduleOnce(1 second) {
simpleActor ! InitialMessage
}
즉, 위와 같이 implicit
로 암시적으로 선언한다면 자동으로 들어간다.
schedule 메서드는 initialDelay
이후 매 period
마다 블록 내의 행위를 진행시키는 메서드이다.
import scala.concurrent.duration._
val system = ActorSystem("timerSystem)
val simpleActor = system.actorOf(Props[SimpleActor], "simpleActor")
system.scheduler.schedule(1 second, 2 seconds) {
simpleActor ! InitialMessage
} (system.dispatcher)
위의 코드처럼 schedule
은 scheduleOnce처럼 유사하게 코드를 작성하면 된다. 위의 schedule은 1초 후 최초 작업이 시작되며, 2초마다 해당 작업을 반복하는 것을 뜻한다. schedule
역시 period 설정을 위하여 scala.concurrent.duration._
을 임포트시키고, system.dispatcher를 인자로 넘겨주어야 한다. 여기서도 implicit
를 사용한다면 인자를 굳이 넘기지 않아도 된다.
만약 스케줄링을 취소하고 싶다면 해당 스케줄러를 Cancellable
데이터 타입으로
Timer는 자기자신에게 메시지를 일정 기간 단위로 처리하면서 scheduler보다 간단하고 안전한 도구이다. Timer
는 Scheduler와 달리, 액터를 선언할 때 Timer
trait를 믹스인하여 구현한다.
import scala.concurrent.duration._
object TimerBasedSCActor {
case object TimerKey
case object Start
case object Reminder
case object Stop
}
class TimerBasedSCActor extends Actor with ActorLogging with Timers{
import TimerBasedSCActor._
timers.startSingleTimer(TimerKey, Start, 500 millis)
override def receive: Receive = {
case Start =>
log.info("Bootstrapping")
timers.startPeriodicTimer(TimerKey, Reminder, 500 millis)
case Reminder =>
log.info("I am alive")
case Stop =>
log.warning("Stopping")
timers.cancel(TimerKey)
context.stop(self)
}
}
timers는 많이 쓰이는 메서드들로 startSingleTimer(key, message, period)
와 startPeriodicTimer(key, message, period)
가 있다.
startSingleTimer(key, message, period)
는 period
후에 타이머 식별자가 key
인 타이머를 시작시키며, 자기 자신에게 message
를 보내는 타이머이다. 따라서 메시지 핸들러 위에 선언하는 경우가 많다.
startPeriodicTimer 역시 startSingleTimer와 마찬가지로 key, message, period를 인자로 갖는다. 만약, singleTimer가 존재한다면 이를 종료시키고 periodic timer가 실행된다.
cancel은 타이머의 식별 key를 가진 타이머를 종료시키는 메서드이다.