transient-haskell / transient

A full stack, reactive architecture for general purpose programming. Algebraic and monadically composable primitives for concurrency, parallelism, event handling, transactions, multithreading, Web, and distributed computing with complete de-inversion of control (No callbacks, no blocking, pure state)
MIT License
630 stars 28 forks source link

Collect and group have inconsistent behavior in failure case #52

Closed harendra-kumar closed 5 years ago

harendra-kumar commented 7 years ago

Collect and group behave differently for the same failure case. When we are trying to collect more results than the number of tasks we have started collect and group show different behavior. Collect is successful though it returns less results than requested after a long while (When BlockedIndefinitelyOnMVar is caught). On the other hand group fails and stops the computation. Try the following to reproduce:

import Control.Monad.IO.Class (liftIO)
import Data.List (sum)
import Transient.Internals (keep)
import Transient.Indeterminism (choose, collect, group)

main = keep $ do
    --collect 101 squares >>= liftIO . putStrLn . show . sum
    group 101 squares >>= liftIO . putStrLn . show . sum
    where
        squares = do
            x <- choose [1..100]
            return (x * x)
agocorona commented 7 years ago

That is because group is passive and has no timeout. It keeps waiting for enough results as much time as necessary and does not detect that there are no threads left running.

I have to define a new group that is active like collect, or to extend collect to make it optionally iterative. Instead of killing the computation after the result, a flag may indicate it to keep collecting.

harendra-kumar commented 7 years ago

I understand the reason, my basic point is to have a consistent behavior across different APIs so that the behavior remains intuitive and a user does not have to learn the quirks or corner cases of each API.

One way is to make collect return failure (stop) in case there are no more threads before it could collect the requested results. A task either completes or fails, partial completion is not an option.