runBlocking(Dispatchers.IO) inside NanoHTTPD request handlers risks thread starvation
Severity: High
File: feature/file-transfer/src/main/java/com/wanbaohe/file_transfer/server/FileTransferServer.kt:144,327
Two methods use runBlocking to bridge coroutines to the synchronous NanoHTTPD handler:
fun getChatHistoryByChannel(channelId: String): List<ChatMessage> {
return runBlocking(Dispatchers.IO) {
chatDao.getMessagesByChannel(channelId).map { it.toChatMessage() }
}
}
fun listChatSessions(): List<ChatSession> {
return runBlocking(Dispatchers.IO) {
chatDao.listSessionSummaries().map { ... }
}
}
NanoHTTPD already dispatches each request on its own thread pool. Wrapping Room queries in runBlocking(Dispatchers.IO) creates a nested blocking call: the NanoHTTPD thread blocks waiting for a coroutine that itself blocks an IO-dispatcher thread. Under concurrent load (multiple browser tabs requesting history simultaneously), this can exhaust the Dispatchers.IO thread pool (default: 64 threads) and deadlock.
Why it matters
If several browser clients load the chat history page simultaneously, or if a Room migration is in progress, the blocking chain can starve the IO dispatcher and cause the entire server to hang. These methods should either use runBlocking without specifying Dispatchers.IO (since the caller is already off the main thread), or the server should be migrated to Ktor/cio which handles async natively.
runBlocking(Dispatchers.IO)inside NanoHTTPD request handlers risks thread starvationSeverity: High
File:
feature/file-transfer/src/main/java/com/wanbaohe/file_transfer/server/FileTransferServer.kt:144,327Two methods use
runBlockingto bridge coroutines to the synchronous NanoHTTPD handler:NanoHTTPD already dispatches each request on its own thread pool. Wrapping Room queries in
runBlocking(Dispatchers.IO)creates a nested blocking call: the NanoHTTPD thread blocks waiting for a coroutine that itself blocks an IO-dispatcher thread. Under concurrent load (multiple browser tabs requesting history simultaneously), this can exhaust the Dispatchers.IO thread pool (default: 64 threads) and deadlock.Why it matters
If several browser clients load the chat history page simultaneously, or if a Room migration is in progress, the blocking chain can starve the IO dispatcher and cause the entire server to hang. These methods should either use
runBlockingwithout specifyingDispatchers.IO(since the caller is already off the main thread), or the server should be migrated to Ktor/cio which handles async natively.