In Ktor, requests are handled asynchronously with coroutines at the Route level. Considering this architecture, is there a necessity or advantage to marking service and repository functions as suspend?
Specifically, when discussing end-to-end call flows from Routes to repositories and back, how do suspend functions enhance performance or design, given Ktor's coroutine-based request handling? This question focuses on scenarios where functions are primarily invoked by Routes, excluding other types of calls to services or repositories.
I think you have a misconception of what coroutines and suspend functions do. Marking a function as
suspenddoesn't change too much on its own. By addingsuspendto a function, we basically add a technical capability to wait for something without blocking the thread. But if we don't use this functionality, then effectively we don't change anything.If you pick a regular service/repository function and simply add
suspendto it, without changing its code, then you changed almost nothing (1). That would be also confusing, because you say a function may suspend the execution, but in fact, it can't. Also, if the function ever blocks the thread, then this is really bad, because suspend functions are expected to never block the thread.So a simple answer is: no, we shouldn't mark functions as
suspendonly because they are executed in a coroutine context. Even your Route functions don't need / shouldn't be suspendable if you don't use coroutines in them. We should mark functions as suspendable if their implementation really suspends the execution. Examples of potentially suspendable operations are: waiting a fixed time, forking into multiple subtasks and waiting on them, waiting on another coroutines, e.g. on locks, performing non-blocking I/O, etc. But only if they wait by suspending and not by blocking the thread.By looking at this from another angle, we can say a suspendable function provides more capabilities to its internal code, but it is harder to call from the external perspective. If you need these additional capabilities, then you need to mark the function with
suspend. If you don't need these capabilities, you generally shouldn't mark the function. Also, by marking Route functions as suspend, you allow to easily and efficiently call other suspend functions from them.(1) One exception to what was said above are client frameworks that generate implementations of functions based on their signature. One example is the Room library. In this case by marking a function as
suspendwe actually change its auto-generated implementation, so such function become truly suspendable.