github typelevel/cats-effect v2.2.0-RC1

latest releases: v3.7.0-RC1, v3.6.3, v3.6.2...
pre-release5 years ago

This is the seventh major release in the Cats Effect 2.x lineage and the first release candidate for a minor release in this line. It is fully binary compatible with all 2.x.y releases. As previously noted, this is the first Cats Effect release to be exclusively published for ScalaJS 1.x; there are no 0.6.x cross-releases.

This is a relatively large release with a few major changes, which is why we're following a release candidate process. We expect 2.2.0 final to be released within a few weeks, depending on feedback. Despite the "release candidate" moniker, we do not anticipate any serious issues with this release; please try it out and report any problems as soon as possible!

Notable New Features

Asynchronous Tracing

IO tracing is probably the single most-requested Cats Effect feature, and it's finally here! Thanks to the tireless work of @RaasAhsan, IO now has a basic, high-performance asynchronous tracing mechanism. Note that this mechanism has very different internals from the async tracing already available in Akka and ZIO, and thus comes with a different set of tradeoffs. Also please remember that no async tracing on the JVM is perfectly accurate, and you may see misleading trace frames depending on your program. Despite all this, the added information is very welcome and sometimes quite helpful in tracking down issues!

This is what it looks like:

IOTrace: 13 frames captured, 0 omitted
  ├ flatMap at org.simpleapp.example.Example.run (Example.scala:67)
  ├ flatMap at org.simpleapp.example.Example.program (Example.scala:57)
  ├ flatMap at org.simpleapp.example.Example.program (Example.scala:58)
  ├ flatMap at org.simpleapp.example.Example.program (Example.scala:59)
  ├ flatMap at org.simpleapp.example.Example.program (Example.scala:60)
  ├ async at org.simpleapp.example.Example.program (Example.scala:60)
  ├ flatMap at org.simpleapp.example.Example.program (Example.scala:61)
  ├ flatMap at org.simpleapp.example.Example.program (Example.scala:60)
  ├ flatMap at org.simpleapp.example.Example.program2 (Example.scala:51)
  ├ map at org.simpleapp.example.Example.program2 (Example.scala:52)
  ├ map at org.simpleapp.example.Example.program (Example.scala:60)
  ├ map at org.simpleapp.example.Example.program (Example.scala:62)
  ╰ flatMap at org.simpleapp.example.Example.run (Example.scala:67)

It's important to understand that this feature is very new and we have a lot of things we want to improve about it! We need user feedback to guide this process. Please file issues and/or chat us up in Gitter if you have ideas, and especially if you see problems!

Tracing has three modes:

  • Disabled
  • Cached (the default)
  • Full

These are all governed by the cats.effect.stackTracingMode system property and are global to the JVM. As a rough performance reference, at present, Cached tracing imposes a roughly 10% performance penalty in synthetic benchmarks on asynchronous IOs. This difference should be entirely impossible to observe outside of microbenchmarks (though we would love to hear otherwise if you see evidence to the contrary!). Full tracing imposes an exceptionally high performance cost, and is expected to be used only in development environments when specifically attempting to track down bugs. Disabled tracing imposes an extremely negligible penalty, and should be used in production if Cached tracing imposes a noticeable performance hit. It is recommended that you stick with the default tracing mode in most cases.

Cached tracing produces a single linear trace of the actions an IO program takes. This tracing mode uses heuristics to determine call-site information on functions like flatMap and async, and those heuristics can be misleading, particularly when used with monad transformers or types like Resource or Stream. If you have ideas for how to improve these heuristics, please let us know!

Full tracing captures a full JVM stack-trace for every call into IO, which results in an extremely comprehensive picture of your asynchronous control flow. This imposes a significant performance cost, but it makes it possible to see through complex compositions such as monad transformers or third-party code. This is an appropriate mode for development when the heuristics which generate a Cached trace are insufficient or misleading.

The IO.traced function produces a backtrace from the call-site, and this object provides a printFiberTrace effect which renders the trace to standard error. The number of actions to retain in the trace can be configured by the system property cats.effect.traceBufferSize, which defaults to 128.

We want your feedback! There are so many different things that we can do with this functionality, and we want your opinions on how it should work and how it can be improved. We have many more features coming, but please file issues, talk to us, try it out, tweet angrily, you know the drill.

Please note that this API is new in 2.2.0-RC1 and we may make changes to it before 2.2.0 final is released. Tracing support is also not yet enabled in ScalaJS.

Bracket Forwarders

This is a rather subtle issue, but on 2.1.x (and earlier), it is impossible to write something like the following:

def foo[F[_]: Sync] =
  Bracket[OptionT[F, *], Throwable].bracket(...)

The Bracket instance would fail to resolve, despite the fact that there's a Sync in scope, since Bracket cannot be inductively defined (see #860 for some discussion of the issues surrounding inductive Bracket instances). This change adds implicit forwarders to the Bracket companion object so that the inductive Sync instances, defined on the Sync companion object, could be resolved via the Bracket companion. Basically, this just moves the Sync instances into a scope wherein they can be addressed by implicit search starting from either Sync or Bracket.

There is a very small chance this will cause implicit ambiguities in some codebases. We are not aware of any specific cases where this can happen, but it's worth keeping in mind as you upgrade.

User-Facing Pull Requests

Special thanks to each and every one of you!

Don't miss a new cats-effect release

NewReleases is sending notifications on new releases.