§Examples

§Using User Quotas in a standalone Play application

The simplest configuration for User Quotas is in a single Play instance. This configuration will track user account usage for the single instance of Play. This configuration is suitable for simple standalone websites and while using Play in development mode.

§Step 1: Get a Lightbend Developer Subscription ID

You will need a license ID. You can either use your existing Lightbend subscription license or get a Trial Developer License ID. Instructions are here:

§Step 2: Create a Play application or update your existing application

You can create a new Play application by downloading the example User Quotas project from Github:

Or you can create a Play project without User Quotas and add the library dependency by hand.

Before you move to the next step you should check that your application builds and runs correctly.

§Step 3: Add the play-quota library dependency to your application

Now that you have a working Play project, you can update it to use the User Quotas feature.

Edit your build.sbt file and add the following library dependency:


// Recommend at least Akka 2.4.14 val akkaVersion = "2.4.14" libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-actor" % akkaVersion, "com.typesafe.akka" %% "akka-slf4j" % akkaVersion, "com.typesafe.akka" %% "akka-cluster" % akkaVersion, "com.typesafe.akka" %% "akka-contrib" % akkaVersion ) libraryDependencies += "com.lightbend.quota" %% "play-quota" % "1.0.0" resolvers += Resolver.url("lightbend-bintray", url("http://dl.bintray.com/lightbend/commercial-releases"))(Resolver.ivyStylePatterns)

§Step 4: Configure User Quotas

You can configure the play-quota library in your application.conf file. We’ll explain all the settings later, but for now here is a simple configuration that you can use:

play.quota.action.default {
  requestCost = 1

  judge {
    # Use a local in-memory judge
    type = memory
    # We set a rate of 50 requests every 5 minutes. This should
    # block robots but not normal users.
    userQuotas {
      type = fixed
      quota {
        maxBalance = 50
        refillAmount = 50
        tickSize = 5 minutes
      }
    }
  }

  # Use IP addresses as users
  userExtractor {
    type = ipAddress
  }

  # Format like Twitter
  resultFormatter {
    type = rest
  }

  # Use flake ids
  correlationIdExtractor {
    type = flakeId    
  }
}

§Step 5: Update your controllers to use quota actions

Now that you’ve configured the play-quota library you can update your controllers to use actions that enforce the quota.

import javax.inject._
import play.api._
import play.api.mvc._
import play.quota.sapi._

class Application @Inject() (quotaAction: QuotaAction) extends Controller {

  def index = quotaAction {
    Ok(views.html.index("Hello world!"))
  }

}

§Step 6: Test your application

When your run your application this action will have service quotas enforced.

Using httpie (http://httpie.org) you can see the effect below:

$ http --headers GET http://localhost:9000
HTTP/1.1 200 OK
Content-Length: 6652
Content-Type: text/html; charset=utf-8
Date: Sun, 20 Sep 2015 03:28:07 GMT
X-Correlation-Id: 9ABIYFLjqjayoZWdtY
X-Rate-Limit-Limit: 50
X-Rate-Limit-Remaining: 2
X-Rate-Limit-Reset: 1442719800

When the limit is exceeded, instead of a 200 OK response, a 429 response is returned:

$ http --headers GET http://localhost:9000
HTTP/1.1 429 Too Many Requests
Content-Length: 0
Date: Sun, 20 Sep 2015 04:18:59 GMT
X-Correlation-Id: 9ABIYV4bODOXa3dBPE
X-Rate-Limit-Limit: 50
X-Rate-Limit-Remaining: 0
X-Rate-Limit-Reset: 1442722800

These quotas are enforced for each IP address. Each IP address can make 50 requests every 5 minutes. Rate limiting information is presented to the user using typical REST headers.

Note that usage information is stored in memory. When you restart your Play instance, all usage information will be cleared.

All of this is customizable, as we can see in the Customization section. But first we’ll look at how you can set up a cluster of Play nodes that share usage information between them.

§Using User Quotas in Play using Akka cluster

The process for running User Quotas in Play using an Akka cluster is similar to the process for a standalone instance. You’ll need to add an extra library, write some more configuration and apply the correct incantation to launch a Akka cluster. The Akka clustering options are the same as a normal Akka cluster. The User Quotas configuration is a bit different because we need to track quotas across the cluster.

§Step 1: Get a Lightbend Developer Subscription ID

You will need a license ID. You can either use your existing Lightbend subscription license or get a Trial Developer License ID. Instructions are here:

§Step 2: Create a Play application or update your existing application

You can create a new Play application by downloading the example project:

Before you move to the next step you should check that your application builds and runs correctly.

§Step 3: Get your Play applications linked together into an Akka cluster

Each Play application has a built in Akka instance running inside it. You can configure this instance as you would a normal Akka instance, by setting configuration options in the usual places.

Here is minimal configuration that you can put in your application.conf:

play.akka.actor-system = my-app-name

akka.remote.netty.tcp {
  hostname = "127.0.0.1"
  port = 0 # Will be provided by startup script
}
akka {
  actor {
    provider = "akka.cluster.ClusterActorRefProvider"
  }
}
akka.cluster.min-nr-of-members = 3

The seed nodes and remote port are left unspecified since they can vary at runtime, we give them with system variables when we start the server. We could also use separate conf files for each server.

Here are the command line options to use after building your Play application. (If you don’t want to start three server instances, you can set min-nr-of-members = 1 just to verify configuration.)

SCRIPT=target/universal/stage/bin/play-quota-cluster-scala

echo Starting server 1 on HTTP port 9001 and Akka port 2552 in dir var/server1
JAVA_OPTS="-Dhttp.port=9001 \
  -Dplay.server.dir=`pwd`/var/server1 \
  -Dakka.remote.netty.tcp.port=2552 \
  -Dakka.cluster.seed-nodes.0=akka.tcp://[email protected]:2552 \
  -Dakka.cluster.seed-nodes.1=akka.tcp://[email protected]:2553 \
  -Dakka.cluster.seed-nodes.2=akka.tcp://[email protected]:2554" $SCRIPT &

echo Starting server 2 on HTTP port 9002 and Akka port 2553 in dir var/server2
JAVA_OPTS="-Dhttp.port=9002 \
  -Dplay.server.dir=`pwd`/var/server2 \
  -Dakka.remote.netty.tcp.port=2553 \
  -Dakka.cluster.seed-nodes.0=akka.tcp://[email protected]:2552 \
  -Dakka.cluster.seed-nodes.1=akka.tcp://[email protected]:2553 \
  -Dakka.cluster.seed-nodes.2=akka.tcp://[email protected]:2554" $SCRIPT &

echo Starting server 3 on HTTP port 9003 and Akka port 2554 in dir var/server3
JAVA_OPTS="-Dhttp.port=9003 \
  -Dplay.server.dir=`pwd`/var/server3 \
  -Dakka.remote.netty.tcp.port=2554 \
  -Dakka.cluster.seed-nodes.0=akka.tcp://[email protected]:2552 \
  -Dakka.cluster.seed-nodes.1=akka.tcp://[email protected]:2553 \
  -Dakka.cluster.seed-nodes.2=akka.tcp://[email protected]:2554" $SCRIPT &

General information about Akka clustering is available here:

§Step 4: Add the play-quota library dependency to your application

Now that you have a working project, you can update it to use the User Quotas feature.

Edit your build.sbt file and add the following library dependencies:


// Recommend at least Akka 2.4.14 val akkaVersion = "2.4.14" libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-actor" % akkaVersion, "com.typesafe.akka" %% "akka-slf4j" % akkaVersion, "com.typesafe.akka" %% "akka-cluster" % akkaVersion, "com.typesafe.akka" %% "akka-contrib" % akkaVersion ) libraryDependencies ++= Seq( "com.lightbend.quota" %% "play-quota" % "1.0.0", "com.lightbend.quota" %% "akka-quota" % "1.0.0" ) resolvers += Resolver.url("lightbend-bintray", url("http://dl.bintray.com/lightbend/commercial-releases"))(Resolver.ivyStylePatterns)

The play-quota dependency adds Play support for User Quotas, the akka-quota dependency brings in Akka support.

§Step 5: Configure User Quotas

You can configure the play-quota library in your application.conf file. We’ll explain all the settings later, but for now here is an example configuration that you can use:

play.quota.action.default {
  requestCost = 1

  judge {
    type = actorAdapter
    judgeActor {
      type = consistentHashing
      actorName = hashing
      numberOfInstances = 100
      allowLocalRoutees = true
      routeeJudgeActor {
        type = judgeAdapter
        actorName = memory
        judge {
          # Use a local in-memory judge
          type = memory
          # We set a rate of 50 requests every 5 minutes. This should
          # block robots but not normal users.
          userQuotas {
            type = fixed
            quota {
              maxBalance = 50
              refillAmount = 50
              tickSize = 5 minutes
            }
          }
        }
      }
    }
  }

  # Use IP addresses as users
  userExtractor {
    type = ipAddress
  }

  # Format like Twitter
  resultFormatter {
    type = rest
  }

  # Use flake ids
  correlationIdExtractor {
    type = flakeId
  }
}

§Step 6: Update your controllers to use quota actions

Now that you’ve configured the User Quotas libraries, you can update your controllers to use actions that enforce the quota.

import javax.inject._
import play.api._
import play.api.mvc._
import play.quota.sapi._

class Application @Inject() (quotaAction: QuotaAction) extends Controller {

  def index = quotaAction {
    Ok(views.html.index("Your new application is ready."))
  }

}

§Step 7: Test your application

When you run your application, this action will have service quotas enforced. Usage will be calculated correctly, even if you use different Play instances in the cluster.

Using httpie (http://httpie.org) you can see the effect below:

$ http --headers GET http://localhost:9001
HTTP/1.1 200 OK
...
X-Rate-Limit-Limit: 50
X-Rate-Limit-Remaining: 49
X-Rate-Limit-Reset: 1442719800
$ http --headers GET http://localhost:9002
HTTP/1.1 200 OK
...
X-Rate-Limit-Limit: 50
X-Rate-Limit-Remaining: 48
X-Rate-Limit-Reset: 1442719800
$ http --headers GET http://localhost:9003
HTTP/1.1 200 OK
...
X-Rate-Limit-Limit: 50
X-Rate-Limit-Remaining: 47
X-Rate-Limit-Reset: 1442719800

When the limit is exceeded, instead of a 200 OK response, a 429 response is returned:

$ http --headers GET http://localhost:9001
HTTP/1.1 429 Too Many Requests
...
X-Rate-Limit-Limit: 50
X-Rate-Limit-Remaining: 0
X-Rate-Limit-Reset: 1442722800

These quotas are enforced for each IP address. Each IP address can make 50 requests every 5 minutes. Rate limiting information is presented to the user using typical REST headers.