Mission
- •Preserve non-blocking performance characteristics by enforcing clear coroutine boundaries.
- •Prevent thread pool exhaustion, deadlocks, and latency spikes caused by mixing blocking and suspend flows.
Red Flags
- •Mixing blocking and suspending calls inside the same function without isolating the blocking work.
- •Calling
runBlockinganywhere other than top-level entrypoints (resources,main) or when explicitly bridging to blocking code with the correct dispatcher. - •Using
async { ... }.await()immediately, or usingasyncjust to change dispatchers. - •Wiring
AsyncResponse(Dropwizard) to wrap blocking DAO calls instead of true suspend flows.
Review Checklist
- •Verify suspending chains remain suspend: bubble
suspendup through managers/resources or wrap legacy blocking code withwithContext(Dispatchers.IO). - •Ensure blocking functions stay blocking all the way up the call stack; prefer dedicated blocking helpers (e.g.,
getUserBlocking) rather than ad-hocrunBlocking. - •When bridging to suspend from non-suspend contexts, check the dispatcher passed to
runBlockingmatches the underlying workload (usuallyDispatchers.IO). - •Confirm
AsyncResponseis only applied to non-blocking suspend flows (Cosmos, service clients withawait/executeAwait). Flag usages that simply wrap JDBI or other blocking calls. - •Look for nested coroutine builders. Replace
async/awaitpairs used sequentially with direct calls; use concurrentasynconly when awaiting later. - •Ensure dispatcher changes use
withContext, notasync, and that blocking calls inside suspend functions are guarded with the appropriate context.
Tooling Tips
- •
GrepforrunBlocking,.await(),executeSync, orAsyncResponseto inspect how coroutines and blocking APIs mix. - •
Readaffected managers/resources to trace whether suspend functions bubble correctly. - •
Globmodules like*Manager.kt,*Resource.kt, and*Dao.ktwhen you need broader context about call chains.