This is the fifty-seventh release in the Cats Effect 3.x lineage. It is fully binary compatible with every 3.x release and fully source-compatible with the 3.6.x lineage.
Warning
Please note that Cats Effect 3.6.x is targeting Scala Native 0.4.x, which means it does not at present support native multithreading. This was a very intentional choice meant to give us an opportunity to break binary compatibility only on Scala Native if necessary when upgrading to Scala Native 0.5 and as we discover the impacts of the integrated runtime on the downstream ecosystem. It also reduces risk since Native multithreading in the runtime is a significant lift and we want to make sure we isolate that change from the already significant changes in 3.6.0. This functionality has already merged into the development branch and we plan to release it in 3.7.0 as soon as possible.
What's Changed
This release addresses a performance issue since 3.6.0 that was reported to be somewhat severe in applications which leverage asynchronous I/O without using the new polling system. Extensive discussion of this issue can be found in #4328. While a workaround was possible, the regression was certainly undesirable. We've changed the polling logic to be considerably less aggressive. In particular, threads will only poll if the polling system has outstanding events which require polling. This means that any applications which make no use of the polling system should see marginal (if any) overhead relative to pre-3.6 versions of Cats Effect, while applications which lean heavily on the new integrated runtime will still see the full benefits thereof.
Note that there is a somewhat pathological case here where an application makes use of the polling system (usually via some dependency, like Skunk or Ember), but does not make heavy use of that code path while simultaneously making very heavy use of other asynchronous I/O mechanisms (such as Netty or Blaze, often indirectly via other dependencies). In this scenario, the worker threads will be forced to make the more expensive polling syscalls, but those calls will often yield very small or empty batches while the majority of the work is enqueued externally (via other async I/O mechanisms). This will result in meaningful overhead relative to the theoretical optimal behavior.
We made the conscious decision in 3.6.0 to prioritize the performance of the integrated runtime, and while we certainly still want all use cases to behave as optimally as possible, this does mean that we occasionally needed to make some tradeoffs in order to achieve the performance goals we had in mind. Our hope is that as the ecosystem continues to adapt to the use of the integrated runtime (particularly with the rise of Scala Native 0.5, where there are essentially no other viable options), these edge cases will become quite rare.
Enhancements
Bug Fixes
- Make
IO#syncStep
interpreter stack-safe by @pantShrey in #4352 - Set
mayInterruptIfRunning = true
when cancelingCompletableFuture
by @istreeter in #4375 - Retrieve suspended fiber count directly through the WSTP by @iRevive in #4406
- Handle
EPOLLHUP
inEpollSystem
by @rahulrangers in #4422 - Dynamically bypass selector polling if no I/O events are present by @djspiewak in #4377
- Fix #4367: Wrap tracingEvents in Option to handle NPE by @pantShrey in #4380
- PoC for not using a CHM in #4388 by @durban in #4426
- Fix #4382: Fix thread leak in WSTP by replacing LinkedTransferQueue with SynchronousQueue and ConcurrentHashMap by @pantShrey in #4388
- Update the main thread detection logic by @iRevive in #4407
Documentation
- Update tutorial.md by @xdev-developer in #4371
- Fixed the sample code inconsistency in
IOLocal
scaladoc by @arinal in #4391 - Add doc for
IOApp#pollingSystem
by @armanbilge in #4222
Behind the Scenes
- Update versions for 3.6.1 by @armanbilge in #4363
- Fix sbt scalafmt check by @armanbilge in #4373
New Contributors
- @xdev-developer made their first contribution in #4371
- @pantShrey made their first contribution in #4352
- @istreeter made their first contribution in #4375
- @arinal made their first contribution in #4391
- @rahulrangers made their first contribution in #4422
Full Changelog: v3.6.1...v3.6.2