Scalatra
Akka
Futures
Programming
Scala

Scalatra 2.1 Akka Futures Example

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Scalatra, futures are used to keep request-handling code non-blocking when the real work finishes later. In the Scalatra 2.x style, that usually means mixing in FutureSupport, providing an execution context, and returning an AsyncResult whose is member is a Future. Akka often supplies the actor system and dispatcher that back those futures.

Why Futures Matter in a Scalatra Route

If a route blocks on slow I/O or expensive computation, request threads can pile up quickly. Futures let the servlet container release the request while the work finishes asynchronously.

That is especially useful for:

  • calling another service
  • waiting on a database or queue
  • running longer computations without blocking the main request thread

In older Scalatra applications, Akka was a common choice for providing the execution environment.

Basic Scalatra Future Pattern

Here is the core structure:

scala
1import org.scalatra._
2import scala.concurrent.{ExecutionContext, Future}
3
4class ExampleServlet extends ScalatraServlet with FutureSupport {
5  protected implicit def executor: ExecutionContext =
6    scala.concurrent.ExecutionContext.global
7
8  get("/hello") {
9    new AsyncResult {
10      val is: Future[String] = Future {
11        Thread.sleep(200)
12        "hello from a future"
13      }
14    }
15  }
16}

The important pieces are:

  • 'FutureSupport enables async route handling'
  • 'executor provides the execution context'
  • 'AsyncResult wraps the future result'

Without that pattern, simply creating a future inside the route does not automatically make the route asynchronous in the way Scalatra expects.

Using an Akka Actor System Dispatcher

If your app already uses Akka, its dispatcher is a better fit than ExecutionContext.global.

scala
1import akka.actor.ActorSystem
2import org.scalatra._
3import scala.concurrent.{ExecutionContext, Future}
4
5class ExampleServlet(system: ActorSystem) extends ScalatraServlet with FutureSupport {
6  protected implicit def executor: ExecutionContext = system.dispatcher
7
8  get("/time") {
9    new AsyncResult {
10      val is: Future[String] = Future {
11        s"current time: ${System.currentTimeMillis()}"
12      }
13    }
14  }
15}

This keeps async execution aligned with the rest of the Akka-based application.

Returning JSON from a Future

Async routes are not limited to plain strings. You can render JSON or other response types the same way.

scala
1import akka.actor.ActorSystem
2import org.json4s.{DefaultFormats, Formats}
3import org.scalatra._
4import org.scalatra.json._
5import scala.concurrent.{ExecutionContext, Future}
6
7class UserServlet(system: ActorSystem)
8  extends ScalatraServlet
9  with JacksonJsonSupport
10  with FutureSupport {
11
12  protected implicit lazy val jsonFormats: Formats = DefaultFormats
13  protected implicit def executor: ExecutionContext = system.dispatcher
14
15  get("/user/:id") {
16    contentType = formats("json")
17
18    new AsyncResult {
19      val is: Future[Map[String, Any]] = Future {
20        Map("id" -> params("id"), "name" -> "Mina")
21      }
22    }
23  }
24}

The async structure stays the same. Only the response type changes.

Keep Blocking Work Out of the Default Dispatcher

A common mistake is to wrap blocking work in a future and assume that makes it harmless. It does not. If the future still blocks a shared dispatcher thread, the application can degrade under load.

If the work is blocking:

  • use a dedicated dispatcher when possible
  • keep the blocking section narrow
  • avoid CPU-heavy or I/O-heavy work on the wrong execution context

Futures are about concurrency, not magic performance.

Common Pitfalls

The first common mistake is returning a raw Future from a route without the proper Scalatra async support structure. In classic Scalatra patterns, AsyncResult is what tells the framework how to manage the async response.

Another issue is forgetting to provide an implicit execution context. Without it, futures will not compile cleanly.

Some code also uses Thread.sleep in examples and then carries that style into production. Real applications should wait on real async work or isolate blocking behavior carefully.

Finally, be careful with error handling. A failed future should map to an appropriate HTTP response rather than silently bubbling into a generic failure path.

Summary

  • In Scalatra 2.x, async routes typically use FutureSupport plus AsyncResult.
  • Provide an implicit execution context, often from an Akka actor system dispatcher.
  • Put the future into the is member of AsyncResult.
  • Async responses can return strings, JSON, or other normal response payloads.
  • Futures help avoid blocking request threads, but blocking work still needs careful execution-context management.

Course illustration
Course illustration

All Rights Reserved.