Skip to content

Commit

Permalink
add asynchronous scalatra servlet and play2-mini server
Browse files Browse the repository at this point in the history
  • Loading branch information
earldouglas committed Sep 11, 2012
1 parent 23d5e50 commit 34f3efe
Show file tree
Hide file tree
Showing 15 changed files with 118 additions and 51 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -8,3 +8,4 @@ target/
bin/
project/target/
project/project/
dist/
9 changes: 9 additions & 0 deletions play2-mini/build.sbt
@@ -0,0 +1,9 @@
name := "scamper-play2-mini"

version := "0.1-SNAPSHOT"

resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"

libraryDependencies += "com.typesafe" %% "play-mini" % "2.0.3"

mainClass in (Compile, run) := Some("play.core.server.NettyServer")
29 changes: 29 additions & 0 deletions play2-mini/src/main/resources/application.conf
@@ -0,0 +1,29 @@
play {
akka {
actor {
deployment {
/actions {
router = round-robin
nr-of-instances = 100
}
/promises {
router = round-robin
nr-of-instances = 100
}
}
retrieveBodyParserTimeout = 5 seconds
actions-dispatcher = {
fork-join-executor {
parallelism-factor = 100
parallelism-max = 100
}
}
promises-dispatcher = {
fork-join-executor {
parallelism-factor = 100
parallelism-max = 100
}
}
}
}
}
6 changes: 6 additions & 0 deletions play2-mini/src/main/scala/Global.scala
@@ -0,0 +1,6 @@
import play.api.Configuration
import com.typesafe.config.ConfigFactory

object Global extends com.typesafe.play.mini.Setup(scamper.App) {
override def configuration: Configuration = Configuration(ConfigFactory.load("application.conf"))
}
37 changes: 37 additions & 0 deletions play2-mini/src/main/scala/scamper/App.scala
@@ -0,0 +1,37 @@
package scamper

import com.typesafe.play.mini.Application
import com.typesafe.play.mini.GET
import com.typesafe.play.mini.Path

import play.api.mvc.Action
import play.api.mvc.PlainResult
import play.api.mvc.ResponseHeader
import play.api.mvc.SimpleResult

object App extends Application {

def route = {
case GET(Path("/simple")) => simple()
case GET(Path("/slow")) => slow()
}

protected def response(code: Int, body: String, `type`: String): PlainResult = {
new SimpleResult[String](header = ResponseHeader(code),
body = play.api.libs.iteratee.Enumerator(body))
.as(`type`)
.withHeaders(("Access-Control-Allow-Origin", "*"))
}

def simple() = Action { implicit request =>
response(200, "<h1>simple</h1>", "text/html")
}

def slow() = Action { implicit request =>
val start = System.currentTimeMillis
Thread.sleep(200)
val stop = System.currentTimeMillis
response(200, "<h1>slept for %d ms</h1>".format(stop - start), "text/html")
}

}
Expand Up @@ -6,25 +6,18 @@ import play.api.mvc.ResponseHeader
import play.api.mvc.SimpleResult
import play.api.mvc.Action
import java.util.Date
import play.Configuration
import play.api.Play

object ScamperController extends Controller {

protected def jsonResponse(body: String): PlainResult = jsonResponse(200, body)
protected def jsonResponse(code: Int, body: String): PlainResult = response(code, body, "application/json")

protected def textResponse(body: String): PlainResult = textResponse(200, body)
protected def textResponse(code: Int, body: String): PlainResult = response(code, body, "text/plain")

protected def response(code: Int, body: String, `type`: String): PlainResult = {
new SimpleResult[String](header = ResponseHeader(code),
body = play.api.libs.iteratee.Enumerator(body))
.as(`type`)
.withHeaders(("Access-Control-Allow-Origin", "*"))
}

protected def attempt(f: => PlainResult): PlainResult =
try { f } catch { case _ => textResponse(400, """{"success":false}""") }

def simple() = Action { implicit request =>
response(200, "<h1>simple</h1>", "text/html")
}
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion play-2/project/Build.scala → play2/project/Build.scala
Expand Up @@ -4,7 +4,7 @@ import PlayProject._

object ApplicationBuild extends Build {

val appName = "scamper-play-2"
val appName = "scamper-play2"
val appVersion = "0.1"

val main = PlayProject(appName, appVersion, Seq.empty, mainLang = SCALA)
Expand Down
File renamed without changes.
File renamed without changes.
45 changes: 4 additions & 41 deletions scamper.jmx
Expand Up @@ -15,12 +15,12 @@
<collectionProp name="Arguments.arguments">
<elementProp name="threadCount" elementType="Argument">
<stringProp name="Argument.name">threadCount</stringProp>
<stringProp name="Argument.value">1000</stringProp>
<stringProp name="Argument.value">500</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="loopCount" elementType="Argument">
<stringProp name="Argument.name">loopCount</stringProp>
<stringProp name="Argument.value">1</stringProp>
<stringProp name="Argument.value">2</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="endpoint" elementType="Argument">
Expand Down Expand Up @@ -110,49 +110,12 @@
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="servlet" enabled="true">
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP Request" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">localhost</stringProp>
<stringProp name="HTTPSampler.port">9002</stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${endpoint}</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
<stringProp name="TestPlan.comments"> </stringProp>
</HTTPSamplerProxy>
<hashTree/>
</hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">${loopCount}</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">${threadCount}</stringProp>
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
<longProp name="ThreadGroup.start_time">1347296476000</longProp>
<longProp name="ThreadGroup.end_time">1347296476000</longProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="async" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">localhost</stringProp>
<stringProp name="HTTPSampler.port">9003</stringProp>
<stringProp name="HTTPSampler.port">9000</stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
Expand Down
20 changes: 20 additions & 0 deletions servlet-3.0/src/main/scala/scamper/Scamper.scala
Expand Up @@ -62,6 +62,26 @@ class ScamperScalatraServlet extends ScalatraServlet {
}
}

class AsyncScamperScalatraServlet extends ScalatraServlet {

override def handle(req: HttpServletRequest, res: HttpServletResponse) {
AsyncExecutor.execute(req.startAsync())(super.handle(req, res))
}

get("/scalatra-async/simple") {
contentType = "text/html"
<h1>simple</h1>
}

get("/scalatra-async/slow") {
contentType = "text/html"
val start = System.currentTimeMillis
Thread.sleep(200)
val stop = System.currentTimeMillis
<h1>slept for { stop - start } ms</h1>
}
}

object Launcher extends App {

val server = new Server()
Expand Down
9 changes: 9 additions & 0 deletions servlet-3.0/src/main/webapp/WEB-INF/web.xml
Expand Up @@ -32,4 +32,13 @@
<url-pattern>/scalatra/*</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>scalatra-async</servlet-name>
<servlet-class>scamper.AsyncScamperScalatraServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>scalatra-async</servlet-name>
<url-pattern>/scalatra-async/*</url-pattern>
</servlet-mapping>

</web-app>

0 comments on commit 34f3efe

Please sign in to comment.