https://kotlinlang.org logo
#getting-started
Title
# getting-started
i

Ishlahul Hanif

09/24/2023, 8:02 AM
Hi, I've been working on my multiplatform library for quite some times now The nature of this library is basically to feed data back to the user every 5 sec (for example), but I don' want the user/caller to be concerned about this 'routine'. Since the
fetching
task should run on background, I'm planning to use coroutine for this task. this is the simplified version of the implementation:
Copy code
public fun startWatch() {
    // check if the job is already running
    if (job.isActive) {
        println("Coroutine task is already running.") 
        return
    }

    // get new value from remote & update existing array
    fetchAndUpdate()

    // launch coroutine that periodically get and set value
    coroutineScope.launch {
        delay(FETCH_DELAY_DURATION_MILLI_SECOND) // for example, 5 sec
        fetchAndUpdate()
    }
}

private fun fetchAndUpdate() {
    // get new value from remote
    val newValue = remoteProvider.getValue()
    internalMem = newValue
}

public fun getValue(): Values {
    return internalMem
}
if possible, I don't wish the caller of
getValue()
nor
startWatch()
is concerned about coroutine, and just care about the value they would get the user/caller only need to
startWatch()
and then use
getValue()
when they need the value my question: 1. is running a coroutine in library acceptable? if not, how should Implement the 'background schedule' behaviour? 2. is there anything I should be aware of regarding atomicity if this function is called in multiple thread? should the
internalMem
be atomic? I'm not sure because the value should only be changed every 5 sec, and most of the time the old value would still be reliable 3. is there any threading annotation I should mark? many thanks guys!
c

CLOVIS

09/24/2023, 6:42 PM
I recommend you read this article: https://arrow-kt.io/learn/resilience/retry-and-repeat/ W.r.t your questions:
is running a coroutine in a library acceptable?
Yes, but the user of the library should control its lifetime. There are two main cases: • "the user may want to stop the operation, e.g. when the user goes to another screen that doesn't use the library" → take a
Job
as parameter, and ensure all background tasks you start inherit from it (example: tasks started using the CoroutineContext from the caller, so only the Job is necessary). • "the user may want to control the thread pool, the delays, etc" → take a
CoroutineScope
as parameter (example)
is there anything I should be aware of regarding atomicity if this function is called in multiple thread?
It really depends what you're doing. In general, shared mutable state is bad: it's better to have a coroutine with the only purpose of storing the value, such that it's never mutable from everywhere else.
is there any threading annotation I should mark?
No, coroutines do not require threading annotations, since those are for protecting shared mutable state, and we don't have any 🙂
c

Casey Brooks

09/24/2023, 7:06 PM
if possible, I don’t wish the caller of getValue() nor startWatch() is concerned about coroutine
Users of the library would likely find this more frustrating than helpful. I’d recommend making
startWatch
take a
CoroutineScope
parameter, so users are fully aware that it’s running in the background, and can customize it it needed. Likewise, I’d store the value in a
StateFlow
so it’s clear to users that the value might be updated over time. They can then opt-in to reactivity by collecting the flow, or they can just use
stateFlow.value
to get it immediately
2