Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion frameworks/Kotlin/ktor/Readme.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
See subprojects

* [Ktor](ktor/) Ktor using traditional JDBC using various servers
* [Ktor-asyncdb](ktor-asyncdb/) Ktor with Netty-based PostgreSQL clients
* [Ktor-jasync](ktor-asyncdb/) Ktor with Netty-based PostgreSQL clients
* [Ktor-r2dbc](ktor-r2dbc/) Ktor with R2DBC for reactive database access
* [Ktor-exposed](ktor-exposed/) Ktor with the Exposed database abstraction library
* [Ktor-pgclient](ktor-pgclient/) Ktor with Reactive PostgreSQL Client
8 changes: 4 additions & 4 deletions frameworks/Kotlin/ktor/benchmark_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
"query_url": "/query/?queries=",
"fortune_url": "/fortunes",
"update_url": "/updates?queries=",
"port": 8080,
"port": 9090,
"approach": "Realistic",
"classification": "Fullstack",
"database": "Postgres",
Expand All @@ -125,7 +125,7 @@
"update_url": "/updates?queries=",
"fortune_url": "/fortunes",

"port": 8080,
"port": 9090,
"approach": "Realistic",
"classification": "Micro",
"database": "Postgres",
Expand All @@ -145,7 +145,7 @@
"query_url": "/queries?queries=",
"update_url": "/updates?queries=",
"fortune_url": "/fortunes",
"port": 8080,
"port": 9090,
"approach": "Realistic",
"classification": "Micro",
"database": "postgres",
Expand All @@ -164,7 +164,7 @@
"exposed-dao": {
"db_url": "/db",
"fortune_url": "/fortunes",
"port": 8080,
"port": 9090,
"approach": "Realistic",
"classification": "Micro",
"database": "postgres",
Expand Down
7 changes: 4 additions & 3 deletions frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ repositories {
}

application {
mainClass.set("MainKt")
mainClass = "io.ktor.server.netty.EngineMain"
}

val ktor_version = "2.3.12"
val kotlinx_serialization_version = "1.7.3"
val ktor_version = "3.1.2"
val kotlinx_serialization_version = "1.8.1"

dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinx_serialization_version")
Expand All @@ -26,6 +26,7 @@ dependencies {
implementation("io.ktor:ktor-server-default-headers:$ktor_version")
implementation("io.ktor:ktor-server-html-builder:$ktor_version")
implementation("com.github.jasync-sql:jasync-postgresql:2.2.4")
implementation("ch.qos.logback:logback-classic:1.5.12")
}

java {
Expand Down
10 changes: 10 additions & 0 deletions frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/Models.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import kotlinx.serialization.Serializable

@Serializable
data class Message(val message: String)

@Serializable
data class World(val id: Int, var randomNumber: Int)

@Serializable
data class Fortune(val id: Int, var message: String)
20 changes: 20 additions & 0 deletions frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/Responses.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import kotlinx.serialization.json.Json

// Optimized JSON instance with better performance settings
internal val json = Json {
prettyPrint = false
isLenient = true
ignoreUnknownKeys = true
coerceInputValues = true
}

internal suspend inline fun <reified E> RoutingCall.respondJson(response: E) {
respond(TextContent(
json.encodeToString(response),
ContentType.Application.Json
))
}
90 changes: 32 additions & 58 deletions frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,16 @@ import com.github.jasync.sql.db.QueryResult
import com.github.jasync.sql.db.SuspendingConnection
import com.github.jasync.sql.db.asSuspending
import com.github.jasync.sql.db.postgresql.PostgreSQLConnectionBuilder
import io.ktor.http.ContentType
import io.ktor.server.application.*
import io.ktor.server.engine.embeddedServer
import io.ktor.server.html.*
import io.ktor.server.netty.Netty
import io.ktor.server.plugins.defaultheaders.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import kotlinx.coroutines.*
import kotlinx.html.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.lang.IllegalArgumentException
import kotlin.random.Random
import kotlin.random.nextInt

@Serializable
data class Message(val message: String)

@Serializable
data class World(val id: Int, val randomNumber: Int)

data class Fortune(val id: Int, val message: String)

val rand = Random(1)

interface Repository {
Expand Down Expand Up @@ -121,57 +106,46 @@ class FortuneTemplate(private val fortunes: List<Fortune>, private val main: Mai
}
}

fun main(args: Array<String>) {
val db = when(args.firstOrNull()) {
"jasync-sql" -> JasyncRepository()
else -> throw IllegalArgumentException("Must specify a postgres client")
}
fun Application.main() {

val server = embeddedServer(Netty, 8080, configure = {
shareWorkGroup = true
}) {
install(DefaultHeaders)
routing {
get("/plaintext") {
call.respondText("Hello, World!")
}
val db = JasyncRepository()

get("/json") {
call.respondText(
Json.encodeToString(Message("Hello, World!")),
ContentType.Application.Json
)
}
install(DefaultHeaders)
routing {
get("/plaintext") {
call.respondText("Hello, World!")
}

get("/db") {
call.respondText(Json.encodeToString(db.getWorld()), ContentType.Application.Json)
}
get("/json") {
call.respondJson(Message("Hello, World!"))
}

get("/query/") {
val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1
val worlds = (1..queries).map { db.getWorld() }
call.respondText(Json.encodeToString(worlds), ContentType.Application.Json)
}
get("/db") {
call.respondJson(db.getWorld())
}

get("/fortunes") {
val newFortune = Fortune(0, "Additional fortune added at request time.")
val fortunes = db.getFortunes().toMutableList()
fortunes.add(newFortune)
fortunes.sortBy { it.message }
call.respondHtmlTemplate(FortuneTemplate(fortunes)) { }
}
get("/query/") {
val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1
val worlds = (1..queries).map { db.getWorld() }
call.respondJson(worlds)
}

get("/updates") {
val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1
val worlds = (1..queries).map { db.getWorld() }
val newWorlds = worlds.map { it.copy(randomNumber = rand.nextInt(1..10000)) }
get("/fortunes") {
val newFortune = Fortune(0, "Additional fortune added at request time.")
val fortunes = db.getFortunes().toMutableList()
fortunes.add(newFortune)
fortunes.sortBy { it.message }
call.respondHtmlTemplate(FortuneTemplate(fortunes)) { }
}

db.updateWorlds(newWorlds)
get("/updates") {
val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1
val worlds = (1..queries).map { db.getWorld() }
val newWorlds = worlds.map { it.copy(randomNumber = rand.nextInt(1..10000)) }

call.respondText(Json.encodeToString(newWorlds), ContentType.Application.Json)
}
db.updateWorlds(newWorlds)

call.respondJson(newWorlds)
}
}

server.start(wait = true)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
ktor {
deployment {
port = 9090
autoreload = false
watch = [ ]
shareWorkGroup = true
}

application {
modules = [MainKt.main]
}
}
21 changes: 21 additions & 0 deletions frameworks/Kotlin/ktor/ktor-asyncdb/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<neverBlock>true</neverBlock>
<appender-ref ref="STDOUT" />
</appender>


<root level="INFO">
<appender-ref ref="ASYNC"/>
</root>

<logger name="org.eclipse.jetty" level="INFO"/>
<logger name="io.netty" level="INFO"/>

</configuration>
2 changes: 1 addition & 1 deletion frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ repositories {
mavenCentral()
}

val ktorVersion = "3.1.1"
val ktorVersion = "3.1.2"
val kotlinxSerializationVersion = "1.8.0"
val exposedVersion = "0.59.0"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.html.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
Expand Down Expand Up @@ -70,7 +69,7 @@ enum class ExposedMode {

fun main(args: Array<String>) {
val exposedMode = valueOf(args.first())
embeddedServer(Netty, port = 8080) { module(exposedMode) }.start(wait = true)
embeddedServer(Netty, port = 9090) { module(exposedMode) }.start(wait = true)
}

fun Application.module(exposedMode: ExposedMode) {
Expand Down
2 changes: 1 addition & 1 deletion frameworks/Kotlin/ktor/ktor-pgclient.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ FROM amazoncorretto:21-al2023-headless
WORKDIR /app
COPY --from=build /app/build/libs/ktor-pgclient.jar ktor-pgclient.jar

EXPOSE 8080
EXPOSE 9090

CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "ktor-pgclient.jar"]
12 changes: 6 additions & 6 deletions frameworks/Kotlin/ktor/ktor-pgclient/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,27 @@ The client features batching, pipelining and supports coroutines.

### Plain Text Test

http://localhost:8080/plaintext
http://localhost:9090/plaintext

### JSON Encoding Test

http://localhost:8080/json
http://localhost:9090/json

### Single Query Test

http://localhost:8080/db
http://localhost:9090/db

### Multiple Queries Test

http://localhost:8080/query?queries=
http://localhost:9090/query?queries=

### Database updates Test

http://localhost:8080/updates?queries=
http://localhost:9090/updates?queries=

### Fortunes Test

http://localhost:8080/fortunes
http://localhost:9090/fortunes

## build

Expand Down
7 changes: 4 additions & 3 deletions frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,21 @@ repositories {
}

application {
mainClass.set("MainKt")
mainClass = "io.ktor.server.netty.EngineMain"
}

val ktor_version = "2.3.12"
val ktor_version = "3.1.2"
val vertx_version = "4.5.11"

dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1")
implementation("io.ktor:ktor-server-netty:$ktor_version")
implementation("io.ktor:ktor-server-html-builder-jvm:$ktor_version")
implementation("io.ktor:ktor-server-default-headers-jvm:$ktor_version")
implementation("io.vertx:vertx-pg-client:$vertx_version")
implementation("io.vertx:vertx-lang-kotlin:$vertx_version")
implementation("io.vertx:vertx-lang-kotlin-coroutines:$vertx_version")
implementation("ch.qos.logback:logback-classic:1.5.12")
}

java {
Expand Down
10 changes: 10 additions & 0 deletions frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/Models.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import kotlinx.serialization.Serializable

@Serializable
data class Message(val message: String)

@Serializable
data class World(val id: Int, var randomNumber: Int)

@Serializable
data class Fortune(val id: Int, var message: String)
20 changes: 20 additions & 0 deletions frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/Responses.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import kotlinx.serialization.json.Json

// Optimized JSON instance with better performance settings
internal val json = Json {
prettyPrint = false
isLenient = true
ignoreUnknownKeys = true
coerceInputValues = true
}

internal suspend inline fun <reified E> RoutingCall.respondJson(response: E) {
respond(TextContent(
json.encodeToString(response),
ContentType.Application.Json
))
}
Loading
Loading