scala - How does spray.routing.HttpService dispatch requests? -
disclaimer: have no scala experience now, question connected basics.
consider following example (it may incomplete):
import akka.actor.{actorsystem, props} import akka.io.io import spray.can.http import akka.pattern.ask import akka.util.timeout import scala.concurrent.duration._ import akka.actor.actor import spray.routing._ import spray.http._ object boot extends app { implicit val system = actorsystem("my-actor-system") val service = system.actorof(props[myactor], "my") implicit val timeout = timeout(5.seconds) io(http) ? http.bind(service, interface = "localhost", port = 8080) } class myactor extends actor myservice { def actorreffactory = context def receive = runroute(myroute) } trait myservice extends httpservice { val myroute = path("my") { post { complete { "pong" } } } }
my question is: happens when control reaches complete
block? question seems general, let me split it.
- i see creation of single actor in example. mean application single-threaded , uses 1 cpu core?
- what happens if blocking call inside
complete
? - if p. 1 true , p. 2 block, how dispatch requests utilize cpus? see 2 ways: actor per request , actor per connection. second 1 seems reasonable, cannot find way using spray library.
- if previous question irrelevant,
detach
directive do? , passing function returning futurecomplete
directive? difference between detach , passing function returning future? - what proper way configure number of working threads , balance requests/connections?
it great if point me explanations in official documentation. extensive , believe missing something.
thank you.
it's answered here mathias - 1 of spray authors. copying reply reference:
in end thing completes request call
requestcontext.complete
. thereby doesn't matter thread or actor context call made from. matters happen within configured "request-timeout" period. can of course issue call in way or another, spray gives number of pre-defined constructs maybe fit architecture better passing actual requestcontext around. these are:
- the
complete
directive, provides sugar on top of "raw"ctx => ctx.complete(…)
function literal.- the future marshaller, calls
ctx.complete
future.oncomplete
handler.- the
produce
directive, extracts functiont => unit
can later used complete request instance of custom type.architecturally, in cases, it's idea not have api layer "leak into" core of application. i.e. application should not know api layer or http. should deal objects of own domain model. therefore passing requestcontext directly application core not best solution.
resorting "ask" , relying on future marshaller obvious, understood , rather easy alternative. comes (small) drawback ask comes mandatory timeout check logically isn't required (since spray-can layer takes care of request timeouts). timeout on ask required technical reasons (so underlying promiseactorref can cleaned if expected reply never comes).
another alternative passing requestcontext around
produce
directive (e.g.produce(instanceof[foo]) { completer => …
). extracts function can pass on application core. when core logic callscomplete(foo)
completion logic run , request completed. thereby application core remains decoupled api layer , overhead minimal. drawbacks of approach twofold: first completer function not serializable, cannot use approach across jvm boundaries. , secondly completion logic running directly in actor context of application core, might change runtime behavior in unwanted ways if marshaller[foo] has non-trivial tasks.a third alternative spawn per-request actor in api layer , have handle response coming application core. not have use ask. still, end same problem promiseactorref underlying ask has: how clean if no response ever comes application core? re-request actor have full freedom implement solution question. however, if decide rely on timeout (e.g. via
context.setreceivetimeout
) benefits on "ask" might non-existent.which of described solutions best fits architecture need decide yourself. however, able show, have couple of alternatives choose from.
to answer of specific questions: there single actor/handler services route if make block spray block. means want either complete route or dispatch work using either of 3 options above.
there many examples on web these 3 options. easiest wrap code in future
. check "actor per request" option/example. in end architecture define appropriate way go.
finally, spray runs on top of akka, akka configuration still applies. see hocon reference.conf
, application.conf
actor threading settings.
Comments
Post a Comment