Browse Source

Upgrade http4k + Kotlin, adding tests, switch out templating engine for performance (#3900)

* git ignore and upgrade http4k/kotlin

* upgrade http4k/kotlin

* migrate to function injection instead of hardcoded database

* updated gradle compile -> implementation, and added a couple of tests

* added more tests

* switched to pebble templates

* switch back to using compile in gradle files for prod code

* replace onejar with shadow jar

* uber -> shadowjar task

* set main classname for shadowjars

* switch back to handlebars templates until we can work out what the problem with pebble loading from the classpath is

* upgrade postgresql driver

* need to merge service files in shadowjar for jetty!

* re-migrate to pebble templates now that loading them from a JAR file is working

* jetty already adds a date header, so we switch it off

* remove tests
David Denton 7 years ago
parent
commit
fffe076a29
23 changed files with 80 additions and 84 deletions
  1. 2 1
      frameworks/Kotlin/http4k/.gitignore
  2. 2 4
      frameworks/Kotlin/http4k/apache/build.gradle
  3. 1 1
      frameworks/Kotlin/http4k/apache/src/main/kotlin/Http4kApacheServer.kt
  4. 11 10
      frameworks/Kotlin/http4k/build.gradle
  5. 3 3
      frameworks/Kotlin/http4k/core/build.gradle
  6. 22 21
      frameworks/Kotlin/http4k/core/src/main/kotlin/Database.kt
  7. 2 2
      frameworks/Kotlin/http4k/core/src/main/kotlin/FortunesRoute.kt
  8. 19 16
      frameworks/Kotlin/http4k/core/src/main/kotlin/Http4kBenchmarkServer.kt
  9. 0 1
      frameworks/Kotlin/http4k/core/src/main/resources/FortunesList.hbs
  10. 1 0
      frameworks/Kotlin/http4k/core/src/main/resources/FortunesList.peb
  11. 1 1
      frameworks/Kotlin/http4k/http4k-apache.dockerfile
  12. 1 1
      frameworks/Kotlin/http4k/http4k-netty.dockerfile
  13. 1 1
      frameworks/Kotlin/http4k/http4k-sunhttp.dockerfile
  14. 1 1
      frameworks/Kotlin/http4k/http4k-undertow.dockerfile
  15. 1 1
      frameworks/Kotlin/http4k/http4k.dockerfile
  16. 2 4
      frameworks/Kotlin/http4k/jetty/build.gradle
  17. 1 1
      frameworks/Kotlin/http4k/jetty/src/main/kotlin/Http4kJettyServer.kt
  18. 2 4
      frameworks/Kotlin/http4k/netty/build.gradle
  19. 1 1
      frameworks/Kotlin/http4k/netty/src/main/kotlin/Http4kNettyServer.kt
  20. 2 4
      frameworks/Kotlin/http4k/sunhttp/build.gradle
  21. 1 1
      frameworks/Kotlin/http4k/sunhttp/src/main/kotlin/Http4kSunHttpServer.kt
  22. 2 4
      frameworks/Kotlin/http4k/undertow/build.gradle
  23. 1 1
      frameworks/Kotlin/http4k/undertow/src/main/kotlin/Http4kUndertowServer.kt

+ 2 - 1
frameworks/Kotlin/http4k/.gitignore

@@ -1,4 +1,5 @@
 build
 out
 docker
-.idea
+.idea
+.gradle

+ 2 - 4
frameworks/Kotlin/http4k/apache/build.gradle

@@ -3,7 +3,5 @@ dependencies {
     compile "org.http4k:http4k-server-apache:$http4k_version"
 }
 
-task uber(type: OneJar) {
-    mainClass = "Http4kApacheServerKt"
-    archiveName = 'http4k-apache-benchmark.jar'
-}
+apply plugin: 'application'
+mainClassName = "Http4kApacheServerKt"

+ 1 - 1
frameworks/Kotlin/http4k/apache/src/main/kotlin/Http4kApacheServer.kt

@@ -2,5 +2,5 @@
 import org.http4k.server.ApacheServer
 
 fun main(args: Array<String>) {
-    Http4kBenchmarkServer.start(ApacheServer(9000))
+    Http4kBenchmarkServer().start(ApacheServer(9000))
 }

+ 11 - 10
frameworks/Kotlin/http4k/build.gradle

@@ -1,6 +1,6 @@
 buildscript {
-    ext.kotlin_version = "1.2.31"
-    ext.http4k_version = "3.26.5"
+    ext.kotlin_version = "1.2.50"
+    ext.http4k_version = "3.32.1"
 
     repositories {
         mavenCentral()
@@ -9,16 +9,10 @@ buildscript {
 
     dependencies {
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
-        classpath 'com.github.onslip:gradle-one-jar:1.0.5'
+        classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
     }
 }
 
-plugins {
-    id "com.jfrog.bintray" version "1.7.3"
-    id 'net.saliman.cobertura' version '2.5.2'
-    id 'com.github.kt3k.coveralls' version '2.8.2'
-}
-
 allprojects {
 
     repositories {
@@ -27,7 +21,7 @@ allprojects {
     }
 
     apply plugin: "kotlin"
-    apply plugin: 'gradle-one-jar'
+    apply plugin: 'com.github.johnrengelman.shadow'
 
     sourceCompatibility = JavaVersion.VERSION_1_8
     targetCompatibility = JavaVersion.VERSION_1_8
@@ -35,6 +29,13 @@ allprojects {
     version = project.hasProperty('releaseVersion') ? project.releaseVersion : 'LOCAL'
     group = 'org.http4k'
 
+    shadowJar {
+        baseName = "http4k-${project.name}-benchmark"
+        classifier = null
+        version = null
+        mergeServiceFiles()
+    }
+
     compileTestKotlin {
         kotlinOptions {
             languageVersion = "1.2"

+ 3 - 3
frameworks/Kotlin/http4k/core/build.gradle

@@ -3,8 +3,8 @@ dependencies {
     compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
     compile "org.http4k:http4k-core:$http4k_version"
     compile "org.http4k:http4k-format-jackson:$http4k_version"
-    compile "org.http4k:http4k-template-handlebars:$http4k_version"
+    compile "org.http4k:http4k-template-pebble:$http4k_version"
     compile "org.apache.commons:commons-lang3:3.7"
-    compile "com.zaxxer:HikariCP:2.7.4"
-    compile "org.postgresql:postgresql:42.1.4"
+    compile "com.zaxxer:HikariCP:3.2.0"
+    compile "org.postgresql:postgresql:42.2.2"
 }

+ 22 - 21
frameworks/Kotlin/http4k/core/src/main/kotlin/Database.kt

@@ -3,27 +3,28 @@ import com.zaxxer.hikari.HikariDataSource
 import java.sql.Connection
 import java.sql.PreparedStatement
 import java.sql.ResultSet
+import javax.sql.DataSource
 
-class Database(private val dataSource: javax.sql.DataSource) {
+open class Database(private val dataSource: DataSource) {
 
     companion object {
         operator fun invoke(host: String): Database {
             val postgresqlUrl = "jdbc:postgresql://$host:5432/hello_world?" +
-                "jdbcCompliantTruncation=false&" +
-                "elideSetAutoCommits=true&" +
-                "useLocalSessionState=true&" +
-                "cachePrepStmts=true&" +
-                "cacheCallableStmts=true&" +
-                "alwaysSendSetIsolation=false&" +
-                "prepStmtCacheSize=4096&" +
-                "cacheServerConfiguration=true&" +
-                "prepStmtCacheSqlLimit=2048&" +
-                "traceProtocol=false&" +
-                "useUnbufferedInput=false&" +
-                "useReadAheadInput=false&" +
-                "maintainTimeStats=false&" +
-                "useServerPrepStmts=true&" +
-                "cacheRSMetadata=true"
+                    "jdbcCompliantTruncation=false&" +
+                    "elideSetAutoCommits=true&" +
+                    "useLocalSessionState=true&" +
+                    "cachePrepStmts=true&" +
+                    "cacheCallableStmts=true&" +
+                    "alwaysSendSetIsolation=false&" +
+                    "prepStmtCacheSize=4096&" +
+                    "cacheServerConfiguration=true&" +
+                    "prepStmtCacheSqlLimit=2048&" +
+                    "traceProtocol=false&" +
+                    "useUnbufferedInput=false&" +
+                    "useReadAheadInput=false&" +
+                    "maintainTimeStats=false&" +
+                    "useServerPrepStmts=true&" +
+                    "cacheRSMetadata=true"
 
             val config = HikariConfig()
             config.jdbcUrl = postgresqlUrl
@@ -42,10 +43,10 @@ class Database(private val dataSource: javax.sql.DataSource) {
 fun <T> Connection.withStatement(stmt: String, fn: PreparedStatement.() -> T): T = prepareStatement(stmt).use(fn)
 
 fun <T> ResultSet.toList(fn: ResultSet.() -> T): List<T> =
-    use {
-        mutableListOf<T>().apply {
-            while (next()) {
-                add(fn(this@toList))
+        use {
+            mutableListOf<T>().apply {
+                while (next()) {
+                    add(fn(this@toList))
+                }
             }
         }
-    }

+ 2 - 2
frameworks/Kotlin/http4k/core/src/main/kotlin/FortunesRoute.kt

@@ -5,7 +5,7 @@ import org.http4k.core.Response
 import org.http4k.core.Status.Companion.OK
 import org.http4k.core.with
 import org.http4k.routing.bind
-import org.http4k.template.HandlebarsTemplates
+import org.http4k.template.PebbleTemplates
 import org.http4k.template.ViewModel
 import org.http4k.template.view
 
@@ -15,7 +15,7 @@ data class FortunesList(val items: List<Fortune>) : ViewModel
 
 object FortunesRoute {
 
-    private val viewBody = Body.view(HandlebarsTemplates().CachingClasspath(), TEXT_HTML)
+    private val viewBody = Body.view(PebbleTemplates().CachingClasspath(), TEXT_HTML)
 
     operator fun invoke(database: Database) = "/fortunes" bind GET to {
         val items = database.withStatement("select * from fortune") {

+ 19 - 16
frameworks/Kotlin/http4k/core/src/main/kotlin/Http4kBenchmarkServer.kt

@@ -1,5 +1,6 @@
 import org.apache.commons.lang3.time.FastDateFormat.getInstance
 import org.http4k.core.Filter
+import org.http4k.core.HttpHandler
 import org.http4k.core.then
 import org.http4k.routing.routes
 import org.http4k.server.ServerConfig
@@ -9,27 +10,29 @@ import java.util.TimeZone.getTimeZone
 object Http4kBenchmarkServer {
     private val dateFormat = getInstance("EEE, d MMM yyyy HH:mm:ss 'GMT'", getTimeZone("GMT"))
 
-    private val headers = Filter { next ->
+    private fun headers(addDate: Boolean) = Filter { next ->
         {
             next(it).let {
                 it.headers(listOf(
-                    "Server" to "http4k",
-                    "Date" to dateFormat.format(System.currentTimeMillis()),
-                    "Content-Length" to it.body.length.toString()))
+                        "Server" to "http4k",
+                        "Content-Length" to it.body.length.toString(),
+                        "Date" to if (addDate) dateFormat.format(System.currentTimeMillis()) else null
+                ))
             }
         }
     }
 
-    private val database = Database("tfb-database")
+    operator fun invoke(addDateHeader: Boolean = true, database: Database = Database("tfb-database")) =
+            headers(addDateHeader).then(
+                    routes(
+                            JsonRoute(),
+                            PlainTextRoute(),
+                            FortunesRoute(database),
+                            WorldRoutes.queryRoute(database),
+                            WorldRoutes.updateRoute(database),
+                            WorldRoutes.multipleRoute(database)
+                    )
+            )
+}
 
-    fun start(config: ServerConfig) = headers.then(
-        routes(
-            JsonRoute(),
-            PlainTextRoute(),
-            FortunesRoute(database),
-            WorldRoutes.queryRoute(database),
-            WorldRoutes.updateRoute(database),
-            WorldRoutes.multipleRoute(database)
-        )
-    ).asServer(config).start().block()
-}
+fun HttpHandler.start(config: ServerConfig) = asServer(config).start().block()

+ 0 - 1
frameworks/Kotlin/http4k/core/src/main/resources/FortunesList.hbs

@@ -1 +0,0 @@
-<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>{{#items}}<tr><td>{{id}}</td><td>{{message}}</td></tr>{{/items}}</table></body></html>

+ 1 - 0
frameworks/Kotlin/http4k/core/src/main/resources/FortunesList.peb

@@ -0,0 +1 @@
+<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>{% for item in model.items %}<tr><td>{{item.id}}</td><td>{{item.message}}</td></tr>{% endfor %}</table></body></html>

+ 1 - 1
frameworks/Kotlin/http4k/http4k-apache.dockerfile

@@ -9,5 +9,5 @@ COPY jetty jetty
 COPY netty netty
 COPY sunhttp sunhttp
 COPY undertow undertow
-RUN gradle --quiet build apache:uber
+RUN gradle --quiet build apache:shadowJar
 CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "apache/build/libs/http4k-apache-benchmark.jar"]

+ 1 - 1
frameworks/Kotlin/http4k/http4k-netty.dockerfile

@@ -9,5 +9,5 @@ COPY jetty jetty
 COPY netty netty
 COPY sunhttp sunhttp
 COPY undertow undertow
-RUN gradle --quiet build netty:uber
+RUN gradle --quiet build netty:shadowJar
 CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "netty/build/libs/http4k-netty-benchmark.jar"]

+ 1 - 1
frameworks/Kotlin/http4k/http4k-sunhttp.dockerfile

@@ -9,5 +9,5 @@ COPY jetty jetty
 COPY netty netty
 COPY sunhttp sunhttp
 COPY undertow undertow
-RUN gradle --quiet build sunhttp:uber
+RUN gradle --quiet build sunhttp:shadowJar
 CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "sunhttp/build/libs/http4k-sunhttp-benchmark.jar"]

+ 1 - 1
frameworks/Kotlin/http4k/http4k-undertow.dockerfile

@@ -9,5 +9,5 @@ COPY jetty jetty
 COPY netty netty
 COPY sunhttp sunhttp
 COPY undertow undertow
-RUN gradle --quiet build undertow:uber
+RUN gradle --quiet build undertow:shadowJar
 CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "undertow/build/libs/http4k-undertow-benchmark.jar"]

+ 1 - 1
frameworks/Kotlin/http4k/http4k.dockerfile

@@ -9,5 +9,5 @@ COPY jetty jetty
 COPY netty netty
 COPY sunhttp sunhttp
 COPY undertow undertow
-RUN gradle --quiet build jetty:uber
+RUN gradle --quiet build jetty:shadowJar
 CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "jetty/build/libs/http4k-jetty-benchmark.jar"]

+ 2 - 4
frameworks/Kotlin/http4k/jetty/build.gradle

@@ -3,7 +3,5 @@ dependencies {
     compile "org.http4k:http4k-server-jetty:$http4k_version"
 }
 
-task uber(type: OneJar) {
-    mainClass = "Http4kJettyServerKt"
-    archiveName = 'http4k-jetty-benchmark.jar'
-}
+apply plugin: 'application'
+mainClassName = "Http4kJettyServerKt"

+ 1 - 1
frameworks/Kotlin/http4k/jetty/src/main/kotlin/Http4kJettyServer.kt

@@ -2,5 +2,5 @@
 import org.http4k.server.Jetty
 
 fun main(args: Array<String>) {
-    Http4kBenchmarkServer.start(Jetty(9000))
+    Http4kBenchmarkServer(false).start(Jetty(9000))
 }

+ 2 - 4
frameworks/Kotlin/http4k/netty/build.gradle

@@ -3,7 +3,5 @@ dependencies {
     compile "org.http4k:http4k-server-netty:$http4k_version"
 }
 
-task uber(type: OneJar) {
-    mainClass = "Http4kNettyServerKt"
-    archiveName = 'http4k-netty-benchmark.jar'
-}
+apply plugin: 'application'
+mainClassName = "Http4kNettyServerKt"

+ 1 - 1
frameworks/Kotlin/http4k/netty/src/main/kotlin/Http4kNettyServer.kt

@@ -2,5 +2,5 @@
 import org.http4k.server.Netty
 
 fun main(args: Array<String>) {
-    Http4kBenchmarkServer.start(Netty(9000))
+    Http4kBenchmarkServer().start(Netty(9000))
 }

+ 2 - 4
frameworks/Kotlin/http4k/sunhttp/build.gradle

@@ -2,7 +2,5 @@ dependencies {
     compile project(":core")
 }
 
-task uber(type: OneJar) {
-    mainClass = "Http4kSunHttpServerKt"
-    archiveName = 'http4k-sunhttp-benchmark.jar'
-}
+apply plugin: 'application'
+mainClassName = "Http4kSunHttpServerKt"

+ 1 - 1
frameworks/Kotlin/http4k/sunhttp/src/main/kotlin/Http4kSunHttpServer.kt

@@ -2,5 +2,5 @@
 import org.http4k.server.SunHttp
 
 fun main(args: Array<String>) {
-    Http4kBenchmarkServer.start(SunHttp(9000))
+    Http4kBenchmarkServer().start(SunHttp(9000))
 }

+ 2 - 4
frameworks/Kotlin/http4k/undertow/build.gradle

@@ -3,7 +3,5 @@ dependencies {
     compile "org.http4k:http4k-server-undertow:$http4k_version"
 }
 
-task uber(type: OneJar) {
-    mainClass = "Http4kUndertowServerKt"
-    archiveName = 'http4k-undertow-benchmark.jar'
-}
+apply plugin: 'application'
+mainClassName = "Http4kUndertowServerKt"

+ 1 - 1
frameworks/Kotlin/http4k/undertow/src/main/kotlin/Http4kUndertowServer.kt

@@ -2,5 +2,5 @@
 import org.http4k.server.Undertow
 
 fun main(args: Array<String>) {
-    Http4kBenchmarkServer.start(Undertow(9000))
+    Http4kBenchmarkServer().start(Undertow(9000))
 }