elm-concurrent-task
elm-concurrent-task copied to clipboard
Task cancellation support
Hi folks,
As far as I understand, there's no way to cancel a ConcurrentTask.
I understand that ConcurrentTask main purpose is to run a group of task concurrently that would otherwise be too long to execute while providing a progress feedback.
It sounds very natural to me to be able to interrupt this group of task.
Would it be doable to implement such a feature?
Given some guidance, I could give it a try if that sounds interesting for the project.
Hi @mbaechler, sorry for the late reply, been off the radar for a bit!
Yea that does make sense as functionality.
If a ConcurrentTask fails the rest of the chain aborts, if you could race 2 tasks (which could be a useful feature anyway) you could implement a timeout mechanism. I was messing around just now and you could do something like this:
Racing two Tasks:
type Race x a
= Winner a
| Error x
race : ConcurrentTask x a -> ConcurrentTask x a -> ConcurrentTask x a
race taskA taskB =
-- The result in the `map2` is ignored as one of the subtasks will 'fail' so we can get the first result
ConcurrentTask.map2 (\_ rb -> rb)
(taskA |> ConcurrentTask.mapError Error |> ConcurrentTask.andThen (\ra -> ConcurrentTask.fail (Winner ra)))
(taskB |> ConcurrentTask.mapError Error |> ConcurrentTask.andThen (\rb -> ConcurrentTask.fail (Winner rb)))
|> ConcurrentTask.onError
(\e ->
case e of
Winner result ->
ConcurrentTask.succeed result
Error err ->
ConcurrentTask.fail err
)
Both of the tasks in the map2 "fail" with the result when they're done so you get an answer from the quickest one. If either of them fail for real though (like a normal application error) that will be returned first.
Then you could use race to do whatever timeout or abort logic you like. e.g. taskWithTimeout will always return "took too long"
taskWithTimeout : ConcurrentTask x String
taskWithTimeout =
race
(ConcurrentTask.Process.sleep 1000 |> ConcurrentTask.map (\_ -> "took too long"))
(ConcurrentTask.Process.sleep 2000 |> ConcurrentTask.map (\_ -> "all done"))
Happy for you to have a play around if you think of a different way.