scala - Akka actor system with HTTP interface -
i'm trying create akka system among other things respond http requests. created few actors exchange messages fine. can use akka-http respond http requests. problem in connecting 2 parts.
tl;dr: how talk akka actors during akka-http request processing?
i created single actor responsible bringing http system:
class httpactor extends actor actorlogging { /* implicits elided */ private def inithttp() = { val route: route = path("status") { { complete { "ok" } } } http()(context.system).bindandhandle(route, "localhost", 8080) } private var bound: option[future[http.serverbinding]] = none override def receive = { case httpactor.init => bound match { case some(x) => log.warning("http bootstrapping") case none => bound = some(inithttp(watcher)) } } } object httpactor { case object init }
as may see, actor creates akka-http service on first message receives (no reason, really, in constructor well).
now, during request processing need communicate other actors, , can't working.
my approach:
private def initinteractivehttp() = { val route: route = path("status") { { complete { "ok" } } } ~ path("ask") { { complete { // here interesting 2 lines: val otheractorresponse = someotheractor ? somemessage otheractorresponse.mapto[string] } } http()(context.system).bindandhandle(route, "localhost", 8080) }
this send somemessage
someotheractor
, wait response prior completing request-response cycle. understand, however, messages sent root httpactor
, bad , leads in terms of scalability. ideally create distinct instance of specialized actor every request, fails due akka-http typing. consider following example:
class disposableactor(httpcontext: httpcontext) { override def prestart() = { // ... send questions other actors } override def receive = { case gotalldata(x) => httpcontext.complete(x) } } class httpactorwithdisposables { // there `context` value in scope - we're actor, after private def inithttpwithdisposableactors() = { val route: route = path("status") { { complete { "ok" } } } ~ path("ask") { { httpcontext => val props = props(new disposableactor(httpcontext)) val disposableactor = context.actorof(props, "disposable-actor-name") // have nothing return here } } http()(context.system).bindandhandle(route, "localhost", 8080) }
with approach, can force disposableactor call httpcontext.complete
@ point of time. should correctly end request-response processing cycle. route dsl, however, requires return valid response (or future) inside get
block, approach doesn't work.
your first approach quite alright, actually. ask pattern creates lightweight, disposable actor waits on result (non-blockingly) complete future. things want replicate disposableactor
, main httpactor not stressed this.
if still want use different actor, there completewith
:
completewith(instanceof[string]) { complete => // complete of type string => unit val props = props(new disposableactor(complete)) val disposableactor = context.actorof(props, "disposable-actor-name") // completewith expects return unit }
and in actor, call complete function when have result
class disposableactor(complete: string => unit) { override def receive = { case gotalldata(x) => complete(x) context stop self // don't stop actor } }
Comments
Post a Comment