KAP
Type-safe multi-service orchestration for Kotlin coroutines.
Flat chains, visible phases, compiler-checked argument order.
The Problem¶
You have 11 microservice calls. Some run in parallel, others depend on earlier results. With raw coroutines you get invisible phases, silent bugs, and 30+ lines of boilerplate:
val checkout = coroutineScope {
val dUser = async { fetchUser() }
val dCart = async { fetchCart() }
val dPromos = async { fetchPromos() }
val dInventory = async { fetchInventory() }
val user = dUser.await() // ← move this above async? Silent serialization.
val cart = dCart.await() // ← swap with promos? Same type, no compiler error.
val promos = dPromos.await()
val inventory = dInventory.await()
// ... 20 more lines of shuttle variables
}
The Solution¶
val checkout: CheckoutResult = Async {
kap(::CheckoutResult)
.with { fetchUser() } // ┐
.with { fetchCart() } // ├─ phase 1: parallel
.with { fetchPromos() } // │
.with { fetchInventory() } // ┘
.then { validateStock() } // ── phase 2: barrier
.with { calcShipping() } // ┐
.with { calcTax() } // ├─ phase 3: parallel
.with { calcDiscounts() } // ┘
.then { reservePayment() } // ── phase 4: barrier
.with { generateConfirmation() } // ┐ phase 5: parallel
.with { sendEmail() } // ┘
}
11 service calls. 5 phases. One flat chain. Swap any two .with lines and the compiler rejects it. 130ms total vs 460ms sequential.
Visible Phases
.with = parallel, .then = barrier. The code shape is the execution plan. No guessing where phases begin and end.
Compile-Time Safety
Each .with slot is typed. Swap two same-type services? The compiler catches it. No positional bugs.
Zero Overhead
JMH benchmarks show KAP overhead is indistinguishable from raw coroutines. No reflection, no code generation at runtime.
Multiplatform
JVM, JS, iOS, macOS, Linux. One dependency: kotlinx-coroutines-core.
Resilience Built-In
Schedule, CircuitBreaker, Resource, bracket, timeoutRace, raceQuorum. All composable in the chain.
Arrow Integration
Parallel validation with error accumulation. zipV scales to 22 validators (Arrow maxes at 9).
Modules¶
Pick what you need:
| Module | What you get | Depends on |
|---|---|---|
kap-core |
Kap, with, then, race, traverse, memoize, timeout, recover |
kotlinx-coroutines-core |
kap-resilience |
Schedule, CircuitBreaker, Resource, bracket, timeoutRace, raceQuorum |
kap-core |
kap-arrow |
zipV, withV, validated {}, attempt(), raceEither |
kap-core + Arrow |
dependencies {
implementation("io.github.damian-rafael-lattenero:kap-core:2.3.0")
// Optional
implementation("io.github.damian-rafael-lattenero:kap-resilience:2.3.0")
implementation("io.github.damian-rafael-lattenero:kap-arrow:2.3.0")
}
Benchmarks¶
All claims backed by 119 JMH benchmarks and deterministic virtual-time proofs.
| Dimension | Raw Coroutines | Arrow | KAP |
|---|---|---|---|
| Framework overhead (arity 3) | <0.01ms | 0.02ms | <0.01ms |
| Multi-phase (9 calls, 4 phases) | 180.85ms | 181.06ms | 180.98ms |
| timeoutRace (primary wins) | 180.55ms | -- | 30.34ms |
| Max validation arity | -- | 9 | 22 |