Suspendable Subcommand
rusnasonov opened this issue · 8 comments
Hi! Is the way to write async code in Subcommand, make fun execute
suspendable?
Hello! Now fun execute
isn't suspendable, only inside you can launch coroutines. But what do you exactly try to implement? I can't fins an example of situation when execute function itself should be suspendable. It could be useful if several subcommands could run in parallel. But only one subcommand of the same level can be used in command line (subcommands of subcommand is another level).
yes, you're right - it's useless
Can't agree that suspendable subcommands are useless. For instance I'm writing a cli linux utility which manages our Elasticsearch clusters. I have a linuxMain
where runBlocking
is called and a commonMain
with all logic. So I cannot use sub-commands inside the commonMain
as all the code is suspendable and it is not possible to call it from Subcommand.execute
method.
The only thing I can think of is pass a channel to the sub-command and send a message with options (via offer
method) into the channel. Thus a coroutine on the other side of the channel receive options and will be able to run suspendable code.
Also in my case I could move all the code into linuxMain
but it's not the case for those who has real multiplatform project.
And in the end current API looks inconsistent as for sub-commands it behaves differently.
Do you want to call suspend functions inside execute
? And you can'y launch a coroutine, because it's made in main in platform code? Is parse
method also inside coroutine?
Yes, I want to call suspend functions inside execute
.
It will be better if I make a concise example.
Platform code (linuxMain
in my case):
fun main(args: Array<String>) = runBlocking<Unit> {
try {
run(Curl.create {}, args)
} catch (ex: ElasticsearchException.TransportError) {
println(ex)
exitProcess(1)
}
exitProcess(0)
}
Common code:
suspend fun run(httpClientEngine: HttpClientEngine, args: Array<String>) {
val parser = ArgParser("cluster-manager")
parser.subcommands(ResumeAction(httpClientEngine), SwitchAction(httpClientEngine))
parser.parse(args)
}
class ResumeAction(private val httpClientEngine: HttpClientEngine): Subcommand("resume") {
override fn execute() {
TODO("Cannot use async http client")
}
}
What is the reason why you can't run coroutine inside inside exacute and just call parse
without runBlocking
?
@ilya-g Do you have any opinion connected with this question?
What is the reason why you can't run coroutine inside inside exacute and just call parse without runBlocking?
So I should pass a scope for a coroutine. It seems strange for me that parser needs a coroutine scope.