Ishlahul Hanif
09/24/2023, 8:02 AMfetching
task should run on background, I'm planning to use coroutine for this task.
this is the simplified version of the implementation:
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!CLOVIS
09/24/2023, 6:42 PMis 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 🙂
Casey Brooks
09/24/2023, 7:06 PMif possible, I don’t wish the caller of getValue() nor startWatch() is concerned about coroutineUsers 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