I have a task that runs on a trigger; every time t...
# coroutines
f
I have a task that runs on a trigger; every time the trigger fires, the task runs and generates some result. At some point, when the user performs an action, I want to get the latest task available, but with these conditions: • if a task is in progress, wait for that task to complete, then get its result • if no task is in progress, get the last result The task starts early so whenever the user action is performed, it is guaranteed that at least a task while have started. How can I model this with coroutines? I have implemented it as shown in thread, but I'm not quite satisfied with this solution and I'd like to hear other options; I think there may be a solution with
CompletableDeferred
but I could not quite get it to work.
Copy code
data class Task(/* ... */)
data class Result(/* ... */)

data class TaskWrapper(
    val id: Int,
    val task: Task
)

data class ResultWrapper(
    val id: Int,
    val result: Result,
)

class Sample {
    val counter = AtomicInt(0)
    val taskQueue = MutableSharedFlow<TaskWrapper>(
        extraBufferCapacity = 1, 
        onBufferOverlow = BufferOverflow.DROP_OLDEST,
    )
    val resultQueue = MutableSharedFlow<ResultWrapper>(
        extraBufferCapacity = 1, 
        onBufferOverflow = BufferOverflow.DROP_OLDEST, 
        replay = 1,
    )
    init {
        scope.launch {
            taskQueue
                .map { processTask(it) }
                .collectLastest { result -> resultQueue.tryEmit(result) }
        }
    }
    
    fun trigger(task: Task) {
        taskQueue.trySend(
            TaskWrapper(counter.getAndIncrement(), task)
        )
    }
    
    suspend fun getResult() {
        return taskQueue
        	.filter { it.id == counter.get() }
            .first()
            .result
    }
    
    suspend fun process(taskWrapper: TaskWrapper): ResultWrapper {
        /* ... */
        return ResultWrapper(id = taskWrapper.id, result = result)
    }
}
s
How about this?
Copy code
class Sample {
  lateinit var latest: Deferred<Result>

  fun trigger(task: Task) {
    latest = scope.async { process(task) }
  }

  suspend fun getResult() = latest.await()

  suspend fun process(task: Task): Result = TODO("process task")
}
f
that looks much simpler, I'll give this a try, thanks!