Part 10 · 1 chapters · ~8 min

Capstone: The Ledger API in Kotlin

The shared ledger API capstone in Kotlin with Ktor and Exposed: idempotent transfers under 100 concurrent requests, double-entry postings summing to zero, payouts with unknown outcomes polled in supervised coroutine scopes, and a comparison with the Java capstone on the same acceptance tests.

11

Acceptance

code
./gradlew test --tests '*Acceptance*'
#  ✓ 100 concurrent identical POST /v1/transfers → exactly 1 transfer
#  ✓ Σ postings = 0 for every transfer (Kotest property, 1,000 cases)
#  ✓ payout timed out at the rail → UNKNOWN → only a rail confirmation settles it

// concurrency test with coroutines
@Test fun idempotent() = runBlocking {
    val key = UUID.randomUUID().toString()
    val ids = (1..100).map { async(Dispatchers.IO) { client.createTransfer(req, key).id } }.awaitAll().toSet()
    assertEquals(1, ids.size)
}

// payout polling: one failing payout does not cancel the rest
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
pending.forEach { p -> scope.launch { withTimeout(15.minutes) { pollUntilFinal(p) } } }
CAPSTONE: THE LEDGER API IN KOTLIN
the shared acceptance tests from every language course
idempotency100 concurrent identical requestsproduce exactly one transfer.double entryPostings for every transfer sum tozero.unknown outcomesA timed-out payout never completeswithout rail confirmation.Ktor + ExposedCoroutine handlers, JDBC onDispatchers.IO, Postgres.structured concurrencyPayout polling in supervisedscopes with timeouts.compareSame tests as Java: compare codesize and behaviour.
swipe the figure sideways, or tap expand for full screen
1/4
shared contract
The same acceptance tests as every other language capstone: idempotency under 100 concurrent requests, balanced postings and safe unknown outcomes.
the shared testscompare languages directly