bracket

This page is a reference guide to the bracket family of operators. It describes:

As bracket operators have standard chunk propagation, this is not described.

Behaviour

bracket

The Stream.bracket(acquire)(release) operator constructs a stream from an acquire and release effect. The stream outputs a single element as a result of running acquire. When the stream terminates, the release effect is guaranteed to run, regardless of whether the stream terminates successfully, errors or is cancelled.

The following example shows how Stream.bracket constructs a single element stream. The acquire effect evaluates to a character a, which is outputted. When the stream is done, the release effect IO('b') is evaluated.

Releasing resources mid-program

The release effect is run at the end of the stream's lifetime, not at the end of the entire program.

This is shown in the following example. The streams ab and xy are appended using the ++ operator. Both streams are constructed with release effects.

When stream ab terminates, its release effect IO('b') is evaluated. Note this this is mid-program: the stream resulting from ++ has not terminated.

resource

The Stream.resource operator constructs a stream from a cats.effect.Resource. The acquire and release effects of the resource are run similarly to Stream.bracket.

The following example lifts a resource with an acquire effect of IO('a') and release effect of IO('b') into a stream.

bracketCase

The Stream.bracketCase operator behaves similarly to Stream.bracket, but uses the ExitCase to construct the release effect. The exit case describes how the stream terminated. It is either Errored, Succeeded or Canceled.

The following example shows the exit case of a successful stream.

If an error is raised over the lifetime of the stream, its exit case will be Errored. In the following example, a stream is constructed from bracketCase, and then composed with an error-raising stream using flatMap.

The stream terminates with an exit case of Errored due to the raised error.

If the stream is canceled due to fiber cancelation or interruption, its exit case will be Canceled. In the following example, the stream constructed from bracketCase is composed with a long-running Stream.sleep. It is then composed with a short-running interruptAfter operator. The resulting stream is canceled after 1 second.

Note that the exit case printed by the release effect is Canceled.

onFinalize

The onFinalize operator evaluates a release effect when its input stream terminates.

input.onFinalize(release) is equivalent to Stream.bracket(IO.unit)(release).flatMap(_ => input)

In the following example, an input stream outputs a single a character. Once it is done, the resource effect IO('b'), termed a finalizer, is run.

onFinalizeCase

The onFinalizeCase operator behaves similarly to onFinalize, but uses the exit case of the input stream to construct the release effect. The exit case is calculated similarly to bracketCase.

Error propagation

The acquire and release effects may raise errors. If so, these are propagated to the resulting stream.

Errors raised in acquire

The release effect is only evaluated if the acquire effect was successful. In the following example, the acquire effect raises an error Err.

Note that the release effect IO('b') is never run and the resulting stream terminates with an exit case of Errored.

Errors raised in release

Raising errors in the release effect is not recommended.

If an error is raised in the release effect, the exit case of the resulting stream is Errored. Any finalizers in the resulting stream are executed.