반응형
Akka HelloWorld 구현
build.sbt
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / scalaVersion := "3.3.5"
lazy val root = (project in file("."))
.settings(
name := "HelloAkka",
idePackagePrefix := Some("com.daum.www")
)
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor" % "2.6.20"
)
Akka System Source
package net.daum.www
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
// 메시지 정의
case class Greet(name: String)
// 상태를 갖는 액터
class Greeter extends Actor:
// 상태: 받은 메시지 수
var count = 0
def receive: Receive = {
case Greet(name) =>
count += 1
println(s"[$count 번째] 안녕하세요, $name! 이것은 Akka Classic + Scala 3 예제입니다.")
}
@main def runAkkaClassic(): Unit =
val system: ActorSystem = ActorSystem("HelloClassicSystem")
val greeter: ActorRef = system.actorOf(Props(classOf[Greeter]), "greeter")
greeter ! Greet("태하팍")
greeter ! Greet("카카오")
greeter ! Greet("스칼라")
greeter ! Greet("아카")
Thread.sleep(1000)
system.terminate()
Akka HelloWorld2 - main과 actor를 구분해보자!
Main.scala
// Main.scala
package net.daum.www
import akka.actor.{ActorSystem, Props}
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration.*
import scala.io.StdIn
import scala.util.{Failure, Success}
object Main:
def main(args: Array[String]): Unit =
val system = ActorSystem("HelloSystem")
val helloActor = system.actorOf(Props[HelloActor](), name = "helloActor")
given Timeout = Timeout(3.seconds)
import system.dispatcher
println("Enter a name to greet (or 'exit' to quit):")
var input = StdIn.readLine()
while input != "exit" do
val future = helloActor ? input
future.onComplete {
case Success(response) => println(s"[response] $response")
case Failure(ex) => println(s"[error] ${ex.getMessage}")
}
Thread.sleep(1000) // Wait a bit for response to print before next input
input = StdIn.readLine()
system.terminate()
HelloActor.scala
// HelloActor.scala
package net.daum.www
import akka.actor.{Actor, ActorSystem, Props}
class HelloActor extends Actor {
def receive: Receive = {
case name: String =>
println(s"[Akka] Hello, $name!")
sender() ! s"Hello, $name! (from Akka)"
case _ =>
println("[Akka] Unknown message received")
sender() ! "Unknown message"
}
}
Result
@main def runAkkaClassic(): Unit = ...
- 간단하게 하나의 엔트리포인트 함수만 필요할 때 사용
- Scala 3에서 새롭게 도입된 간결한 메인 함수 정의 방식
- 클래스나 객체 없이 단독 함수로 실행 가능
- 실행 시 runAkkaClassic이라는 이름으로 런타임에 잡힘
- SBT로 run 할 때 자동으로 인식됨
object Main: def main(args: Array[String]): Unit = ...
- Java 스타일의 main 메소드 정의 방식
- 표준 JVM 앱처럼 public static void main(String[] args) 개념
- object 안에 들어가야 함
- def main(args: Array[String]) 형식을 정확히 따라야 함
- Java나 다른 툴들과의 호환성이 좋음
- 여러 main 메서드 중 1개만 선택적으로 실행하고 싶을 때 유용
Akka HTTP 연동해서 api로 호출해보자!
build.sbt
scalaVersion을 3.x에서 2.13.13으로 변경! (akka-http에서 버전 호환이 안맞음!)
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / scalaVersion := "2.13.13"
lazy val root = (project in file("."))
.settings(
name := "HelloAkka",
idePackagePrefix := Some("com.daum.www")
)
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor" % "2.6.20",
"com.typesafe.akka" %% "akka-stream" % "2.6.20",
"com.typesafe.akka" %% "akka-http" % "10.2.10",
"com.typesafe.akka" %% "akka-http-spray-json" % "10.2.10" // JSON 쓰고 싶다면
)
// HelloActor.scala
package net.daum.www
import akka.actor.{Actor, Props}
class HelloActor extends Actor {
def receive: Receive = {
case name: String =>
sender() ! s"Hello, $name! (from Akka)"
case _ =>
sender() ! "Unknown message"
}
}
// Main.scala
package net.daum.www
import akka.actor.{ActorSystem, Props}
import akka.pattern.ask
import akka.util.Timeout
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._
import scala.concurrent.duration._
import scala.concurrent.Future
import scala.io.StdIn
object Main {
def main(args: Array[String]): Unit = {
implicit val system = ActorSystem("HelloSystem")
implicit val executionContext = system.dispatcher
implicit val timeout: Timeout = Timeout(3.seconds)
val helloActor = system.actorOf(Props[HelloActor], name = "helloActor")
val route = path("hello" / Segment) { name =>
get {
val response: Future[String] = (helloActor ? name).mapTo[String]
complete(response)
}
}
val bindingFuture = Http().newServerAt("localhost", 8080).bind(route)
println("Server now online at http://localhost:8080/hello/태하팍\nPress RETURN to stop...")
StdIn.readLine()
bindingFuture
.flatMap(_.unbind())
.onComplete(_ => system.terminate())
}
}
Result
위의 소스는 Akka HTTP와 Akka Actor를 연동한 기본 웹 서버 코드 입니다.
구조
- ActorSystem 생성 → 액터 사용을 위한 환경 준비
- helloActor 생성 → 이름을 입력하면 인사 메시지를 주는 액터
- HTTP 경로 /hello/{name} 등록 → 해당 경로 요청 시 액터에게 메시지를 보내고 응답 받음
- 웹 서버 실행 → localhost:8080 에서 서버 시작
- 콘솔에서 엔터 입력 시 서버 종료
implicit val system = ActorSystem("HelloSystem")
implicit val executionContext = system.dispatcher
implicit val timeout: Timeout = Timeout(3.seconds)
- ActorSystem: 액터를 만들고 관리할 수 있는 환경 (HelloSystem이라는 이름)
- executionContext: 비동기 처리용 스레드풀 (Future 연산 등)
- timeout: ask 패턴에서 응답을 기다릴 시간 설정
액터생성
val helloActor = system.actorOf(Props[HelloActor], name = "helloActor")
Http Route 정의
- GET /hello/{name} 요청이 오면:
- helloActor에 name을 메시지로 전달 (?는 ask 패턴)
- 응답이 Future[String]으로 오면 그대로 클라이언트에게 전송
val route = path("hello" / Segment) { name =>
get {
val response: Future[String] = (helloActor ? name).mapTo[String]
complete(response)
}
}
서버 시작
- HTTP 서버를 localhost:8080에 열고, 앞서 정의한 route에 따라 요청 처리
val bindingFuture = Http().newServerAt("localhost", 8080).bind(route)
서버 유지 및 종료 대기
- 콘솔에서 엔터 치기 전까지 서버는 계속 실행됨
println("Server now online at http://localhost:8080/hello/태하팍")
StdIn.readLine()
서버 종료 처리
- 엔터 입력 시:
- 서버 언바인드 (연결 끊기)
- ActorSystem 종료 (앱 종료)
bindingFuture
.flatMap(_.unbind())
.onComplete(_ => system.terminate())
반응형
'Data Platform > Akka' 카테고리의 다른 글
Akka Classic 뽀개기_Actors(1~4. Actor API) (1) | 2025.04.10 |
---|---|
Akka에서 Actor 생성 시 금지하는 방식 (0) | 2025.03.27 |
Akka Classic 뽀개기_Overview (0) | 2025.03.26 |
Akka Classic (0) | 2025.03.25 |
Akka HelloWorld (0) | 2025.03.24 |