kap-ktor¶
Ktor server integration plugin for KAP. Shared configuration, circuit breakers, tracing, and response helpers.
Unreleased
This module is available in source but not yet published to Maven Central. To use it now, build from source or use a JitPack dependency. Maven Central publication is planned for the next release.
Depends on: kap-core, kap-resilience, ktor-server-core.
Plugin Installation¶
install(Kap) {
tracer = KapTracer { event ->
when (event) {
is TraceEvent.Started -> logger.info("${event.name} started")
is TraceEvent.Succeeded -> logger.info("${event.name} in ${event.duration}")
is TraceEvent.Failed -> logger.error("${event.name} failed", event.error)
}
}
circuitBreaker("user-api", maxFailures = 5, resetTimeout = 30.seconds)
circuitBreaker("payment-api", maxFailures = 3, resetTimeout = 60.seconds)
}
Built-in Tracers¶
// Standard Ktor logger (SLF4J)
install(Kap) {
tracer = application.ktorTracer()
}
// Structured key-value output for JSON logging
install(Kap) {
tracer = application.structuredTracer()
}
Named Circuit Breakers¶
Register circuit breakers once, use them in any route:
install(Kap) {
circuitBreaker("user-api", maxFailures = 5, resetTimeout = 30.seconds)
}
routing {
get("/users/{id}") {
val breaker = call.circuitBreaker("user-api")
val user = Async {
Kap { fetchUser(call.parameters["id"]!!) }
.withCircuitBreaker(breaker)
.retry(Schedule.times(3) and Schedule.exponential(50.milliseconds))
}
call.respond(user)
}
}
Response Helpers¶
respondAsync¶
Execute a KAP computation and respond:
get("/dashboard/{userId}") {
call.respondAsync {
kap(::Dashboard)
.with { fetchUser(userId) }
.with { fetchCart(userId) }
.with { fetchPromos(userId) }
}
}
respondKap¶
Execute any suspend block and respond:
get("/user/{id}") {
call.respondKap {
Async {
kap(::UserResponse)
.with { fetchProfile(id) }
.with { fetchPreferences(id) }
}
}
}
StatusPages Exception Handlers¶
Install KAP-aware exception handlers:
Handles:
| Exception | HTTP Status |
|---|---|
| CircuitBreakerOpenException | 503 Service Unavailable |
| TimeoutCancellationException | 504 Gateway Timeout |
| IllegalArgumentException | 400 Bad Request |
Note
Requires ktor-server-status-pages on your classpath.
Full Example¶
fun Application.module() {
install(ContentNegotiation) { json() }
install(Kap) {
tracer = ktorTracer()
circuitBreaker("user-api", maxFailures = 5, resetTimeout = 30.seconds)
}
install(StatusPages) {
kapExceptionHandlers()
}
routing {
get("/dashboard/{userId}") {
val userId = call.parameters["userId"]!!
val breaker = call.circuitBreaker("user-api")
val tracer = call.kapTracer
val dashboard = Async {
kap(::Dashboard)
.with {
Kap { fetchUser(userId) }
.withCircuitBreaker(breaker)
.traced("fetch-user", tracer)
}
.with { fetchCart(userId) }
.with { fetchPromos(userId) }
}
call.respond(dashboard)
}
}
}
See the ktor-integration example for a complete application with 28 integration tests.