3

This is a follow-up to my old question. Suppose I need to invoke a REST service both synchronously and asynchronously. In the synchronous case I would like to do it on the caller thread without taking other threads from the pool.

I would like to write my business logic only once and reuse it in the both cases. The business logic consists of building a request and handling the response.

I would like also to compose REST invocations, as if in "invoke service A and then service B and then service C"

How would you do it in Scala ?

Community
  • 1
  • 1
Michael
  • 41,026
  • 70
  • 193
  • 341
  • Do you want to achieve it via Akka or using the Java concurrency facilities? Also have you considered Play? –  Feb 08 '15 at 13:53
  • http://stackoverflow.com/questions/6581188/is-there-an-executorservice-that-uses-the-current-thread might give some insight. Then you could pass the "current-thread" executor for the sync case and a real executor with other threads for the async. – Rich Henry Feb 08 '15 at 14:28
  • @I.K. I would prefer Scala to Java. Akka and Play are probably Ok. – Michael Feb 08 '15 at 14:48
  • @RichHenry Yes, I can use `Executor`, `Runnable`, and `Callable` but I am afraid that the resulting code will look so ugly that it does not worth it. – Michael Feb 08 '15 at 14:51
  • Well I thought you would feed that to `ExecutionContext.fromExecutorService` instead of using the global context, and still use `Future` etc. I wasn't suggesting to use the Java types directly. – Rich Henry Feb 08 '15 at 14:55
  • Remember you can control the implicit execution context used by Future and the rest of the Scala APIs, and via this mechanism you can control how threads are created. – Rich Henry Feb 08 '15 at 14:57

1 Answers1

2

This should run in the current thread...

{
  val currentThreadEx = new AbstractExecutorService {
    override def execute(r: Runnable) { r.run }
    override def shutdownNow(): java.util.List[Runnable] = new java.util.ArrayList[Runnable]()
    override def shutdown() {}
    override def isTerminated = false
    override def isShutdown = false
    override def awaitTermination(timeout: Long, unit: TimeUnit) = false
  }
  implicit val exContext = ExecutionContext.fromExecutor(currentThreadEx)

  val f = Future {
    10 + 1
  } 

  println(Await.result(f, 1 seconds))
}

This will run on the default executor...

{
  import ExecutionContext.Implicits.global

  val f = Future {
    10 + 1
  } 

  println(Await.result(f, 1 seconds))
}

As you can see, you can use ExecutorService as the abstraction point.

Or you can use a function written in terms of Monads, and then you can bind those operations together without dealing with the context (i.e. Future).

  def op1[M[_]: Monad](i: Int)(j: Int): M[Int] = {
    Monad[M].point { i * j }
  }

  println(Monad[Id].point(10) >>= op1[Id](10))
  println((Future { 10 } >>= op1[Future](10)).run)
Rich Henry
  • 1,837
  • 15
  • 25
  • Thanks. So you are suggesting implement the business logic as a `Future` and use different `Executors` for sync and async cases. Since `Futures` are composable I can probably compose invocations of different services implemented as `Futures`. Is it correct ? – Michael Feb 09 '15 at 09:55
  • This is one way to do it. And you can compose futures. Scalaz monads could also help switching between Id and Future as the monadic type but I thought that would be to complicated a solution given what you asked. – Rich Henry Feb 09 '15 at 11:50
  • Could you elaborate on how `scalaz` monads may help ? I know `scalaz` a bit and know what monads are. – Michael Feb 09 '15 at 15:17
  • Ill post a simple example above, basically you write your operations in terms of monads and then you can switch which type you use. – Rich Henry Feb 09 '15 at 17:43