findAllItems
    :: ThreadId
    -> (String -> IO ())
    -> b
    -> (b -> IO (Int -> ([a], [b])))
    -> Consumer a IO ()
    -> IO ()
findAllItems mainThreadId logger start next consumer = withSpawn unbounded go
  where
    go (output,input) = do
        requestId <- randomIO :: IO UUID.UUID
        _ <- asyncNextPage output (requestId, start)
        runEffect $ fromInput input >-> loop 1 output >-> consumer
    loop 0 _ = return ()
    loop c output = do
        lift $ logger ("threads: " ++ show c)
        result <- Pipes.await
        let (resultObjects,nextBounds) = result c
        forM_ resultObjects yield
        nextBounds' <-
            lift $
            traverse
                (\x ->
                      (randomIO :: IO UUID) >>=
                      \y ->
                           return (y, x))
                nextBounds
        lift $ forM_ nextBounds' (asyncNextPage output)
        loop (c - 1 + length nextBounds) output
    asyncNextPage output (requestId,bounds) =
        forkIO $
        do logger $ "Starting: " ++ show requestId
           resultEx <- try (next bounds)
           case resultEx of
               Left (ex :: SomeException) -> do
                   logger "Exception"
                   throwTo mainThreadId ex
                   exitFailure
               Right result -> do
                   runEffect $ Pipes.each [result] >-> toOutput output
                   logger $ "Complete: " ++ show requestId
findAllItems
    :: ThreadId
    -> (String -> IO ())
    -> b
    -> (b -> IO (Int -> ([a], [b])))
    -> Consumer a IO ()
    -> IO ()
findAllItems mainThreadId logger start next consumer = withSpawn unbounded go
  where
    go (output,input) = do
        requestId <- randomIO :: IO UUID.UUID
        _ <- asyncNextPage output (requestId, start)
        runEffect $ fromInput input >-> loop 1 output >-> consumer
    loop 0 _ = return ()
    loop c output = do
        lift $ logger ("threads: " ++ show c)
        result <- Pipes.await
        let (resultObjects,nextBounds) = result c
        forM_ resultObjects yield
        nextBounds' <-
            lift $
            traverse
                (\x ->
                      (randomIO :: IO UUID) >>=
                      \y ->
                           return (y, x))
                nextBounds
        lift $ forM_ nextBounds' (asyncNextPage output)
        loop (c - 1 + length nextBounds) output
    asyncNextPage output (requestId,bounds) =
        forkIO $
        do logger $ "Starting: " ++ show requestId
           resultEx <- try (next bounds)
           case resultEx of
               Left (ex :: SomeException) -> do
                   logger "Exception"
                   throwTo mainThreadId ex
                   exitFailure
               Right result -> do
                   runEffect $ Pipes.each [result] >-> toOutput output
                   logger $ "Complete: " ++ show requestId
findAllItems mainThreadId logger start next consumer = withSpawn unbounded go
  where
    go (output,input) = do
        requestId <- randomIO :: IO UUID.UUID
        _ <- asyncNextPage output (requestId, start)
        runEffect $ fromInput input >-> loop 1 output >-> consumer
    loop 0 _ = return ()
    loop c output = do
        lift $ logger ("threads: " ++ show c)
        result <- Pipes.await
        let (resultObjects,nextBounds) = result c
        forM_ resultObjects yield
        nextBounds' <-
            lift $
            traverse
                (\x ->
                      (randomIO :: IO UUID) >>=
                      \y ->
                           return (y, x))
                nextBounds
        lift $ forM_ nextBounds' (asyncNextPage output)
        loop (c - 1 + length nextBounds) output
    asyncNextPage output (requestId,bounds) =
        forkIO $
        do logger $ "Starting: " ++ show requestId
           resultEx <- try (next bounds)
           case resultEx of
               Left (ex :: SomeException) -> do
                   logger "Exception"
                   throwTo mainThreadId ex
                   exitFailure
               Right result -> do
                   runEffect $ Pipes.each [result] >-> toOutput output
                   logger $ "Complete: " ++ show requestId