Throw the exception promptly in bracketIO

This commit is contained in:
Harendra Kumar 2023-08-01 20:22:58 +05:30
parent 1b21c18d4b
commit 87cb22cc99
5 changed files with 59 additions and 13 deletions

View File

@ -10,6 +10,7 @@
* Changed the signature of 'Streamly.Data.Stream.handle' to make the exception
handler monadic.
* Rethrow the exception promptly in bracketIO.
### Deprecations

View File

@ -466,7 +466,16 @@ module Streamly.Data.Stream
-- in Exception.Base
-- * Exceptions
-- | Most of these combinators inhibit stream fusion, therefore, when
-- | Note that the stream exception handling routines catch and handle
-- exceptions only in the stream generation steps and not in the consumer
-- of the stream. For example, if we are folding or parsing a stream - any
-- exceptions in the fold or parse steps won't be observed by the stream
-- exception handlers. Exceptions in the fold or parse steps can be handled
-- using the fold or parse exception handling routines. You can wrap the
-- stream elimination function in the monad exception handler to observe
-- exceptions in the stream as well as the consumer.
--
-- Most of these combinators inhibit stream fusion, therefore, when
-- possible, they should be called in an outer loop to mitigate the cost.
-- For example, instead of calling them on a stream of chars call them on a
-- stream of arrays before flattening it to a stream of chars.
@ -481,8 +490,19 @@ module Streamly.Data.Stream
-- | 'bracket' is the most general resource management operation, all other
-- operations can be expressed using it. These functions have IO suffix
-- because the allocation and cleanup functions are IO actions. For
-- generalized allocation and cleanup functions see the functions without
-- generalized allocation and cleanup functions, see the functions without
-- the IO suffix in the "streamly" package.
--
-- Note that these operations bracket the stream generation only, they do
-- not cover the stream consumer. This means if an exception occurs in
-- the consumer of the stream (e.g. in a fold or parse step) then the
-- exception won't be observed by the stream resource handlers, in that
-- case the resource cleanup handler runs when the stream is garbage
-- collected.
--
-- Monad level resource management can always be used around the stream
-- elimination functions, such a function can observe exceptions in both
-- the stream and its consumer.
, before
, afterIO
, finallyIO

View File

@ -257,6 +257,9 @@ afterIO action (Stream step state) = Stream step' Nothing
-- | Run the action @m b@ if the stream evaluation is aborted due to an
-- exception. The exception is not caught, simply rethrown.
--
-- Observes exceptions only in the stream generation, and not in stream
-- consumers.
--
-- /Inhibits stream fusion/
--
{-# INLINE_NORMAL onException #-}
@ -320,6 +323,8 @@ bracketUnsafe bef aft =
-- stream is abandoned @onGC@ is executed, if the stream encounters an
-- exception @onException@ is executed.
--
-- The exception is not caught, it is rethrown.
--
-- /Inhibits stream fusion/
--
-- /Pre-release/
@ -335,18 +340,20 @@ bracketIO3 bef aft onExc onGC =
gbracket
bef
aft
(\a (e :: SomeException) _ -> onExc a >> return (nilM (MC.throwM e)))
(\a (e :: SomeException) _ -> onExc a >> MC.throwM e)
onGC
(inline MC.try)
-- | Run the alloc action @IO b@ with async exceptions disabled but keeping
-- blocking operations interruptible (see 'Control.Exception.mask'). Use the
-- output @b@ as input to @b -> Stream m a@ to generate an output stream.
-- output @b@ of the IO action as input to the function @b -> Stream m a@ to
-- generate an output stream.
--
-- @b@ is usually a resource under the IO monad, e.g. a file handle, that
-- requires a cleanup after use. The cleanup action @b -> IO c@, runs whenever
-- the stream ends normally, due to a sync or async exception or if it gets
-- garbage collected after a partial lazy evaluation.
-- (1) the stream ends normally, (2) due to a sync or async exception or, (3)
-- if it gets garbage collected after a partial lazy evaluation. The exception
-- is not caught, it is rethrown.
--
-- 'bracketIO' only guarantees that the cleanup action runs, and it runs with
-- async exceptions enabled. The action must ensure that it can successfully
@ -355,6 +362,12 @@ bracketIO3 bef aft onExc onGC =
-- When the stream ends normally or on a sync exception, cleanup action runs
-- immediately in the current thread context, whereas in other cases it runs in
-- the GC context, therefore, cleanup may be delayed until the GC gets to run.
-- An example where GC based cleanup happens is when a stream is being folded
-- but the fold terminates without draining the entire stream or if the
-- consumer of the stream encounters an exception.
--
-- Observes exceptions only in the stream generation, and not in stream
-- consumers.
--
-- /See also: 'bracketUnsafe'/
--
@ -443,6 +456,12 @@ ghandle f stream =
-- | When evaluating a stream if an exception occurs, stream evaluation aborts
-- and the specified exception handler is run with the exception as argument.
-- The exception is caught and handled unless the handler decides to rethrow
-- it. Note that exception handling is not applied to the stream returned by
-- the exception handler.
--
-- Observes exceptions only in the stream generation, and not in stream
-- consumers.
--
-- /Inhibits stream fusion/
--

View File

@ -11,6 +11,8 @@
breaking change in `transformers` 0.6. You can replace `lift` with
`fromEffect` when using these as top level monads in a monad stack.
* Rethrow the exception promptly in bracketIO.
## 0.9.0 (Mar 2023)
Also see the following:

View File

@ -124,7 +124,7 @@ bracket3D bef aft onExc onGC =
gbracket
bef
aft
(\a (e :: SomeException) _ -> onExc a >> return (D.nilM (MC.throwM e)))
(\a (e :: SomeException) _ -> onExc a >> MC.throwM e)
onGC
(inline MC.try)
@ -144,6 +144,8 @@ bracket3D bef aft onExc onGC =
-- stream is abandoned @onGC@ is executed, if the stream encounters an
-- exception @onException@ is executed.
--
-- The exception is not caught, it is rethrown.
--
-- /Pre-release/
{-# INLINE bracket3 #-}
bracket3 :: (MonadAsync m, MonadCatch m)
@ -155,14 +157,16 @@ bracket3 :: (MonadAsync m, MonadCatch m)
-> Stream m a
bracket3 = bracket3D
-- | Run the alloc action @m b@ with async exceptions disabled but keeping
-- | Run the alloc action @IO b@ with async exceptions disabled but keeping
-- blocking operations interruptible (see 'Control.Exception.mask'). Use the
-- output @b@ as input to @b -> Stream m a@ to generate an output stream.
-- output @b@ of the IO action as input to the function @b -> Stream m a@ to
-- generate an output stream.
--
-- @b@ is usually a resource under the state of monad @m@, e.g. a file
-- handle, that requires a cleanup after use. The cleanup action @b -> m c@,
-- runs whenever the stream ends normally, due to a sync or async exception or
-- if it gets garbage collected after a partial lazy evaluation.
-- @b@ is usually a resource under the IO monad, e.g. a file handle, that
-- requires a cleanup after use. The cleanup action @b -> m c@, runs whenever
-- (1) the stream ends normally, (2) due to a sync or async exception or, (3)
-- if it gets garbage collected after a partial lazy evaluation. The exception
-- is not caught, it is rethrown.
--
-- 'bracket' only guarantees that the cleanup action runs, and it runs with
-- async exceptions enabled. The action must ensure that it can successfully