Kotlin cloudflare worker
A library to running kotlin/js on cloudflare worker.
Get started
Setup
kotlinx.coroutinesis required
plugins {
kotlin("multiplatform") version "2.2.21"
}
repositories {
mavenCentral()
maven("https://repo.maven.rtast.cn/releases")
}
// to get latest version of this lib, go to
// https://next.pkg.rtast.cn/#/releases/cn/rtast/kotlin-cfworker/kotlin-cloudflare-worker/
implementation("cn.rtast.kotlin-cfworker:kotlin-cloudflare-worker:1.0.2")
Run app
kotlin {
js(IR) {
nodejs {
outputModuleName = "kotlin-cloudflare-worker"
binaries.executable()
}
}
}
Minimal hello world app
/**
* DO NOT EDIT THIS FUNCTION
*/
fun main() {
@Suppress("unused_expression")
val eventListener = EventListener { event ->
val dyn = event.asDynamic()
event.asDynamic().respondWith(handleRequest(dyn.request as Request))
Unit
}
js("addEventListener('fetch', eventListener)")
}
@JsExport
fun handleRequest(request: Request): Promise<Response> = GlobalScope.promise {
val server = WorkerApplication().apply {
route("/") {
respondText("Hello kotlin cloudflare worker")
}
}
return@promise server.handle(request)
}
Before run worker locally, you need to install wrangler and login
First, create wrangler.toml in your root project and configure it
name = "kotlin-cloudflare-worker" # any name you want
account_id = "<your account id>"
workers_dev = false
preview_urls = false
compatibility_date = "2022-08-11"
main = "kotlin-cloudflare-worker.js" # Set this value same as `outputModuleName`
Then run gradle task gradlew compileProductionExecutableKotlinJs,
copy wrangler.toml into build/compileSync/js/main/productionExecutable/kotlin,
and run wrangler dev command in build/compileSync/js/main/productionExecutable/kotlin,
Deploy
Run gradle task, copy wrangler.toml, but use wrangler deploy to deploy to cloudflare worker
Note
JavaScript uses a single-threaded execution model. All asynchronous work is ultimately driven by the event loop ( including Kotlin coroutines on JS).
Therefore, DO NOT create a CoroutineScope(Dispatchers.Default) or launch CPU-bound coroutines, as there is no real background thread on JS targets.
All coroutines run on same event loop thread, and all coroutines not in same event loop will be dropped.
Example:
// DO NOT DO THIS
val scope = CoroutineScope(Dispatcher.DEFAULT)
fun blockingFunction() {
scope.launch {
// this block will never execute
}
}
// Instead of do this
fun main() {
@Suppress("unused_expression")
val eventListener = EventListener { event ->
val dyn = event.asDynamic()
event.asDynamic().respondWith(handleRequest(dyn.request as Request))
Unit
}
js("addEventListener('fetch', eventListener)")
}
@JsExport
fun handleRequest(request: Request): Promise<Response> = GlobalScope.promise {
return Promise.resolve(Response("Hello"))
}
Http client
Cloudflare worker is not a standard nodejs environment, do http requests must
use fetch api(not window.fetch, this is browser api), use cn.rtast.cfworker.client.fetch instead,
ByteArray and ByteBuffer cast
Kotlin cloudflare worker provided api to mutual conversion,
import cn.rtast.cfworker.util.toByteArray
import cn.rtast.cfworker.util.toArrayBuffer
val bb: ByteBuffer = ...
// convert ByteBuffer to ByteArray
val ba: ByteArray = bb.toByteArray()
// convert ByteArray to ByteBuffer
val bb2: ByteBuffer = ba.toArrayBuffer()
CPU Time limit
Cloudflare worker free tier have a limit of worker cpu limit (10ms, exclude IO waiting time), kotlin cloudflare worker
depends on kotlin-stdlib and kotlinx.coroutines, which are quite heavy*, When performing CPU-bound task,
please carefully consider whether to use JavaScript instead of Kotlin.
But it works for my maven repository, I registered over 15 api endpoints. The avg cpu time for each endpoint does not exceed 10ms, but it may increase significantly during cold start (Over 50-200ms, but still responsible)
This image shows last 24 hours avg cpu time, see
P50
Real instance
Yes, it the maven repository but built with kotlin/js with this lib
