Is there a feasible way to terminate a process if ...
# coroutines
n
Is there a feasible way to terminate a process if it takes too long to execute using Coroutines? Currently I have developed a project that simulates a Serverless platform running two Serverless Functions. The platform terminates the function (process) after intercepting its output from a text stream (a maximum output limit is applied). Serverless Function code (truncated):
Copy code
// ...
if (args.isNotEmpty()) args.forEachIndexed { pos, item -> println("Arg ${pos + 1}: $item") }
    println("Ping")
    println("Pong")
    sleep(4u)
    println("Another item...")
    while (true) {
        usleep(500u)
    }
The function for running the Serverless Function (on the Serverless Platform side):
Copy code
private fun CoroutineScope.runFunction(filePath: String, vararg args: String) = launch(context = Dispatchers.Default) {
    println("Running Serverless Function...")
    val file = openProcess(filePath = filePath, args = args)
    file.readLines(5u).forEach { println(it) }
    val processName = extractProcessName(filePath)
    val pid = fetchLatestPid(processName).toInt()
    if (pid > 0) kill(pid, SIGINT)
    file.closeProcess()
}
Below is some sample output (via a Gradle task):
Copy code
> Task :pipe-reader:runPipe_readerDebugExecutableLinuxX64
Running Serverless Function...
Running Serverless Function...
Arg 1: Testing 1234...
Arg 2: Message A
Arg 3: Hello World! :)
Ping
Pong
Arg 1: Testing 1234...
Arg 2: :)
Ping
Pong
Another item...

BUILD SUCCESSFUL in 6s
If the old Kotlin Native memory model is used then it takes around 10s, and all the Serverless Functions run sequentially instead of being run in parallel.
n
Are you looking for https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-interruptible.html?
Copy code
withTimeout(500L) {            // Cancels coroutine on timeout
    runInterruptible {         // Throws CancellationException if interrupted
        doSomethingBlocking()  // Interrupted on coroutines cancellation
    }
}
👌 1
👍 1
n
The
runInterruptible
function is along the lines of what I am looking for. Unfortunately this function isn't available on the Kotlin Native side ☹️ . @elizarov
I suspect that the function isn't available due to more attention being paid to the Kotlin JVM platform than any other Kotlin development platform (eg Kotlin Native) with the KotlinX Coroutines library.
t
it’s probably because JVM has the concept of
InterruptedException
, it’s more or less just
catch (e: InterruptedException) { throw CancellationException() }
. What would be the equivalent on Native?
n
There isn't anything equivalent on the Kotlin Native side at the thread level. The nearest equivalent at the process level with the Linux targets is Keyboard Interrupt (also known as SIGINT), which usually occurs when the user presses Ctrl+c.
d
if readLines() is blocking (which I suspect it is -- it would need some fancy non-blocking IO integration to not be) then your function is blocking -- so it wont receive cancelations. What you can do is to either kill the process or close the pipe ("file") from a different thread, you can do this purely with threads, or with a seperate coroutine on a threaded dispatcher (like Dispatchers.IO) use Thread.sleep or delay() as apprpreate then either/both close the pipe and/or kill the pid you need that coroutine to be cancelable -- either by coroutine cancelation or thread interrupt depending on how you launched it
👍 1
n
I have come up with a Coroutine that acts like a timer, which sends a Keyboard Interrupt signal to the process after a given duration:
Copy code
suspend fun runProcessTimer(pid: Int, duration: Duration = 3.seconds) = coroutineScope {
    launch {
        delay(duration)
        if (pid > 0 && kill(pid, SIGINT) == 0) println("Process terminated")
    }
}
The function works as intended in the Unix Pipes project ( https://gitlab.com/napperley/unix-pipes ).
d
'Warning' -- assuming SIGINT will terminate a process is asking for problems. SIGINT stands for INTERRUPT not TERMINATE -- It is true that the default behaviour of SIGINT is to terminate the process --- It is not uncommon to trap SIGINT -- very common in terminal/UI programs ... so if by accident you launch say "vi" -- a SIGINT will not terminate it. Its likely these 'oddballs' are precisely the edge cases you wrote the code for. If you want to be sure you terminate the program use SIGKILL (9) or if you want to be nice first use SIGTERM (15) followed by a short delay then SIGKILL Coincidentally -- I was just trying to exit 'kotlinc' -- with a control-C and it didnt exit -- all it did was
>>
>> \
<interrupted>
>>
n
Very strange that kotlinc wouldn't terminate after pressing Ctrl+c. Another way to exit some programs is to use Ctrl+d, which also works with kotlinc.
d
Closing the process input is the same as control-d would produce . (EOF)
Also there is no "Control-D" signal -- control-d is interpreted literally as keyboard input by the tty driver, and causes the stream to be closed. Unlike control-c which is interprted as a interrupt generating control character and causes the tty driver to send a SIGNINT signal. There is no analogous control-D "signal" -- you cant do kill(pid,CONTROL_D)
👍 1