on master help sign in
Throw the exception promptly in bracketIO
87cb22cHarendra Kumar
core/docs/Changelog.md+1
@@ -10,6 +10,7 @@
10
10
11* Changed the signature of 'Streamly.Data.Stream.handle' to make the exception
11* Changed the signature of 'Streamly.Data.Stream.handle' to make the exception
12 handler monadic.
12 handler monadic.
13+* Rethrow the exception promptly in bracketIO.
13
14
14### Deprecations
15### Deprecations
15
16
core/src/Streamly/Data/Stream.hs+22−2
@@ -466,7 +466,16 @@ module Streamly.Data.Stream
466 -- in Exception.Base
466 -- in Exception.Base
467
467
468 -- * Exceptions
468 -- * Exceptions
469+ -- | Note that the stream exception handling routines catch and handle
470+ -- exceptions only in the stream generation steps and not in the consumer
471+ -- of the stream. For example, if we are folding or parsing a stream - any
472+ -- exceptions in the fold or parse steps won't be observed by the stream
473+ -- exception handlers. Exceptions in the fold or parse steps can be handled
474+ -- using the fold or parse exception handling routines. You can wrap the
475+ -- stream elimination function in the monad exception handler to observe
476+ -- exceptions in the stream as well as the consumer.
477+ --
469− -- | Most of these combinators inhibit stream fusion, therefore, when
478+ -- Most of these combinators inhibit stream fusion, therefore, when
470 -- possible, they should be called in an outer loop to mitigate the cost.
479 -- possible, they should be called in an outer loop to mitigate the cost.
471 -- For example, instead of calling them on a stream of chars call them on a
480 -- For example, instead of calling them on a stream of chars call them on a
472 -- stream of arrays before flattening it to a stream of chars.
481 -- stream of arrays before flattening it to a stream of chars.
@@ -481,8 +490,19 @@ module Streamly.Data.Stream
481 -- | 'bracket' is the most general resource management operation, all other
490 -- | 'bracket' is the most general resource management operation, all other
482 -- operations can be expressed using it. These functions have IO suffix
491 -- operations can be expressed using it. These functions have IO suffix
483 -- because the allocation and cleanup functions are IO actions. For
492 -- because the allocation and cleanup functions are IO actions. For
484− -- generalized allocation and cleanup functions see the functions without
493+ -- generalized allocation and cleanup functions, see the functions without
485 -- the IO suffix in the "streamly" package.
494 -- the IO suffix in the "streamly" package.
495+ --
496+ -- Note that these operations bracket the stream generation only, they do
497+ -- not cover the stream consumer. This means if an exception occurs in
498+ -- the consumer of the stream (e.g. in a fold or parse step) then the
499+ -- exception won't be observed by the stream resource handlers, in that
500+ -- case the resource cleanup handler runs when the stream is garbage
501+ -- collected.
502+ --
503+ -- Monad level resource management can always be used around the stream
504+ -- elimination functions, such a function can observe exceptions in both
505+ -- the stream and its consumer.
486 , before
506 , before
487 , afterIO
507 , afterIO
488 , finallyIO
508 , finallyIO
core/src/Streamly/Internal/Data/Stream/StreamD/Exception.hs+23−4
@@ -257,6 +257,9 @@ afterIO action (Stream step state) = Stream step' Nothing
257-- | Run the action @m b@ if the stream evaluation is aborted due to an
257-- | Run the action @m b@ if the stream evaluation is aborted due to an
258-- exception. The exception is not caught, simply rethrown.
258-- exception. The exception is not caught, simply rethrown.
259--
259--
260+-- Observes exceptions only in the stream generation, and not in stream
261+-- consumers.
262+--
260-- /Inhibits stream fusion/
263-- /Inhibits stream fusion/
261--
264--
262{-# INLINE_NORMAL onException #-}
265{-# INLINE_NORMAL onException #-}
@@ -320,6 +323,8 @@ bracketUnsafe bef aft =
320-- stream is abandoned @onGC@ is executed, if the stream encounters an
323-- stream is abandoned @onGC@ is executed, if the stream encounters an
321-- exception @onException@ is executed.
324-- exception @onException@ is executed.
322--
325--
326+-- The exception is not caught, it is rethrown.
327+--
323-- /Inhibits stream fusion/
328-- /Inhibits stream fusion/
324--
329--
325-- /Pre-release/
330-- /Pre-release/
@@ -335,18 +340,20 @@ bracketIO3 bef aft onExc onGC =
335 gbracket
340 gbracket
336 bef
341 bef
337 aft
342 aft
338− (\a (e :: SomeException) _ -> onExc a >> return (nilM (MC.throwM e)))
343+ (\a (e :: SomeException) _ -> onExc a >> MC.throwM e)
339 onGC
344 onGC
340 (inline MC.try)
345 (inline MC.try)
341
346
342-- | Run the alloc action @IO b@ with async exceptions disabled but keeping
347-- | Run the alloc action @IO b@ with async exceptions disabled but keeping
343-- blocking operations interruptible (see 'Control.Exception.mask'). Use the
348-- blocking operations interruptible (see 'Control.Exception.mask'). Use the
349+-- output @b@ of the IO action as input to the function @b -> Stream m a@ to
344−-- output @b@ as input to @b -> Stream m a@ to generate an output stream.
350+-- generate an output stream.
345--
351--
346-- @b@ is usually a resource under the IO monad, e.g. a file handle, that
352-- @b@ is usually a resource under the IO monad, e.g. a file handle, that
347-- requires a cleanup after use. The cleanup action @b -> IO c@, runs whenever
353-- requires a cleanup after use. The cleanup action @b -> IO c@, runs whenever
348−-- the stream ends normally, due to a sync or async exception or if it gets
354+-- (1) the stream ends normally, (2) due to a sync or async exception or, (3)
349−-- garbage collected after a partial lazy evaluation.
355+-- if it gets garbage collected after a partial lazy evaluation. The exception
356+-- is not caught, it is rethrown.
350--
357--
351-- 'bracketIO' only guarantees that the cleanup action runs, and it runs with
358-- 'bracketIO' only guarantees that the cleanup action runs, and it runs with
352-- async exceptions enabled. The action must ensure that it can successfully
359-- async exceptions enabled. The action must ensure that it can successfully
@@ -355,6 +362,12 @@ bracketIO3 bef aft onExc onGC =
355-- When the stream ends normally or on a sync exception, cleanup action runs
362-- When the stream ends normally or on a sync exception, cleanup action runs
356-- immediately in the current thread context, whereas in other cases it runs in
363-- immediately in the current thread context, whereas in other cases it runs in
357-- the GC context, therefore, cleanup may be delayed until the GC gets to run.
364-- the GC context, therefore, cleanup may be delayed until the GC gets to run.
365+-- An example where GC based cleanup happens is when a stream is being folded
366+-- but the fold terminates without draining the entire stream or if the
367+-- consumer of the stream encounters an exception.
368+--
369+-- Observes exceptions only in the stream generation, and not in stream
370+-- consumers.
358--
371--
359-- /See also: 'bracketUnsafe'/
372-- /See also: 'bracketUnsafe'/
360--
373--
@@ -443,6 +456,12 @@ ghandle f stream =
443
456
444-- | When evaluating a stream if an exception occurs, stream evaluation aborts
457-- | When evaluating a stream if an exception occurs, stream evaluation aborts
445-- and the specified exception handler is run with the exception as argument.
458-- and the specified exception handler is run with the exception as argument.
459+-- The exception is caught and handled unless the handler decides to rethrow
460+-- it. Note that exception handling is not applied to the stream returned by
461+-- the exception handler.
462+--
463+-- Observes exceptions only in the stream generation, and not in stream
464+-- consumers.
446--
465--
447-- /Inhibits stream fusion/
466-- /Inhibits stream fusion/
448--
467--
docs/User/Project/Changelog.md+2
@@ -11,6 +11,8 @@
11 breaking change in `transformers` 0.6. You can replace `lift` with
11 breaking change in `transformers` 0.6. You can replace `lift` with
12 `fromEffect` when using these as top level monads in a monad stack.
12 `fromEffect` when using these as top level monads in a monad stack.
13
13
14+* Rethrow the exception promptly in bracketIO.
15+
14## 0.9.0 (Mar 2023)
16## 0.9.0 (Mar 2023)
15
17
16Also see the following:
18Also see the following:
src/Streamly/Internal/Data/Stream/Exception/Lifted.hs+11−7
@@ -124,7 +124,7 @@ bracket3D bef aft onExc onGC =
124 gbracket
124 gbracket
125 bef
125 bef
126 aft
126 aft
127− (\a (e :: SomeException) _ -> onExc a >> return (D.nilM (MC.throwM e)))
127+ (\a (e :: SomeException) _ -> onExc a >> MC.throwM e)
128 onGC
128 onGC
129 (inline MC.try)
129 (inline MC.try)
130
130
@@ -144,6 +144,8 @@ bracket3D bef aft onExc onGC =
144-- stream is abandoned @onGC@ is executed, if the stream encounters an
144-- stream is abandoned @onGC@ is executed, if the stream encounters an
145-- exception @onException@ is executed.
145-- exception @onException@ is executed.
146--
146--
147+-- The exception is not caught, it is rethrown.
148+--
147-- /Pre-release/
149-- /Pre-release/
148{-# INLINE bracket3 #-}
150{-# INLINE bracket3 #-}
149bracket3 :: (MonadAsync m, MonadCatch m)
151bracket3 :: (MonadAsync m, MonadCatch m)
@@ -155,14 +157,16 @@ bracket3 :: (MonadAsync m, MonadCatch m)
155 -> Stream m a
157 -> Stream m a
156bracket3 = bracket3D
158bracket3 = bracket3D
157
159
158−-- | Run the alloc action @m b@ with async exceptions disabled but keeping
160+-- | Run the alloc action @IO b@ with async exceptions disabled but keeping
159-- blocking operations interruptible (see 'Control.Exception.mask'). Use the
161-- blocking operations interruptible (see 'Control.Exception.mask'). Use the
162+-- output @b@ of the IO action as input to the function @b -> Stream m a@ to
160−-- output @b@ as input to @b -> Stream m a@ to generate an output stream.
163+-- generate an output stream.
161--
164--
162−-- @b@ is usually a resource under the state of monad @m@, e.g. a file
165+-- @b@ is usually a resource under the IO monad, e.g. a file handle, that
163−-- handle, that requires a cleanup after use. The cleanup action @b -> m c@,
166+-- requires a cleanup after use. The cleanup action @b -> m c@, runs whenever
164−-- runs whenever the stream ends normally, due to a sync or async exception or
167+-- (1) the stream ends normally, (2) due to a sync or async exception or, (3)
165−-- if it gets garbage collected after a partial lazy evaluation.
168+-- if it gets garbage collected after a partial lazy evaluation. The exception
169+-- is not caught, it is rethrown.
166--
170--
167-- 'bracket' only guarantees that the cleanup action runs, and it runs with
171-- 'bracket' only guarantees that the cleanup action runs, and it runs with
168-- async exceptions enabled. The action must ensure that it can successfully
172-- async exceptions enabled. The action must ensure that it can successfully