Asynchronous, Reactive Programming for Scala and Scala.js.
This is a minor bug-fixing release for the 3.x series.
Updated dependencies (#1554):
Fixes:
Trampoline.trampolineContext
no longer ignores its parent BlockContext (#1544)executionShadedJCTools
(#1514)This release was made possible by:
The release is binary and source compatible with 3.x series, and was cross-built for the following Scala and ScalaJS versions:
2.12
, 2.13
and 3.0
1.5.1
WARN: we're dropping compatibility with Scala 2.11
and ScalaJS 0.6.x
. If you still need those you'll have to stay on version 3.3.0
.
Changes in this release:
2.11
and Scala.js 0.6.x
2.6.1
2.5.1
3.3.0
Observable.whileBusyAggregateEvents
(#1320)Coeval
and Task
via a more accurate filter (#1353)Observable.throttleLatest
(#1396)Observable
(#1381)This release was made possible by the work and feedback of:
The release is binary and source compatible with 3.x.x line. It is released for the following Scala and ScalaJS versions:
Note that most likely, this is going to be the last release on ScalaJS 0.6.x. We can consider doing backports on-demand.
This release includes a highly requested feature of better stack traces for Task
and Coeval
!
Big thanks to @RaasAhsan and @djspiewak for providing the original implementation that we have ported.
They are enabled by default, but it is configurable. Refer to Stack Traces section for more details.
We have measured about 10-30% performance hit in CACHED mode (the default) in microbenchmarks.
If you have any performance tests, we would greatly appreciate any reports!
If the hit is too big, you can disable the stack traces with -Dmonix.eval.stackTracingMode=none
.
For the following code:
package test.app
import monix.eval.Task
import monix.execution.Scheduler
import cats.implicits._
import scala.concurrent.duration._
object TestTracingApp extends App {
implicit val s = Scheduler.global
def customMethod: Task[Unit] =
Task.now(()).guarantee(Task.sleep(10.millis))
val tracingTestApp: Task[Unit] = for {
_ <- Task.shift
_ <- Task.unit.attempt
_ <- (Task(println("Started the program")), Task.unit).parTupled
_ <- customMethod
_ <- if (true) Task.raiseError(new Exception("boom")) else Task.unit
} yield ()
tracingTestApp.onErrorHandleWith(ex => Task(ex.printStackTrace())).runSyncUnsafe
}
The default (cached) stack trace is going to be:
java.lang.Exception: boom
at test.app.TestTracingApp$.$anonfun$tracingTestApp$5(TestTracingApp.scala:36)
at guarantee @ test.app.TestTracingApp$.customMethod(TestTracingApp.scala:29)
at flatMap @ test.app.TestTracingApp$.$anonfun$tracingTestApp$4(TestTracingApp.scala:35)
at parTupled @ test.app.TestTracingApp$.$anonfun$tracingTestApp$2(TestTracingApp.scala:34)
at parTupled @ test.app.TestTracingApp$.$anonfun$tracingTestApp$2(TestTracingApp.scala:34)
at flatMap @ test.app.TestTracingApp$.$anonfun$tracingTestApp$2(TestTracingApp.scala:34)
at flatMap @ test.app.TestTracingApp$.$anonfun$tracingTestApp$1(TestTracingApp.scala:33)
at flatMap @ test.app.TestTracingApp$.delayedEndpoint$test$app$TestTracingApp$1(TestTracingApp.scala:32)
Before 3.3.0
and with stack traces disabled, stack traces are a mess:
java.lang.Exception: boom
at test.app.TestTracingApp$.$anonfun$tracingTestApp$5(TestTracingApp.scala:36)
at monix.eval.internal.TaskRunLoop$.startFull(TaskRunLoop.scala:188)
at monix.eval.internal.TaskRestartCallback.syncOnSuccess(TaskRestartCallback.scala:101)
at monix.eval.internal.TaskRestartCallback$$anon$1.run(TaskRestartCallback.scala:118)
at monix.execution.internal.Trampoline.monix$execution$internal$Trampoline$$immediateLoop(Trampoline.scala:66)
at monix.execution.internal.Trampoline.startLoop(Trampoline.scala:32)
at monix.execution.schedulers.TrampolineExecutionContext$JVMNormalTrampoline.super$startLoop(TrampolineExecutionContext.scala:142)
at monix.execution.schedulers.TrampolineExecutionContext$JVMNormalTrampoline.$anonfun$startLoop$1(TrampolineExecutionContext.scala:142)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:94)
at monix.execution.schedulers.TrampolineExecutionContext$JVMNormalTrampoline.startLoop(TrampolineExecutionContext.scala:142)
at monix.execution.internal.Trampoline.execute(Trampoline.scala:40)
at monix.execution.schedulers.TrampolineExecutionContext.execute(TrampolineExecutionContext.scala:57)
at monix.execution.schedulers.BatchingScheduler.execute(BatchingScheduler.scala:50)
at monix.execution.schedulers.BatchingScheduler.execute$(BatchingScheduler.scala:47)
at monix.execution.schedulers.AsyncScheduler.execute(AsyncScheduler.scala:31)
at monix.eval.internal.TaskRestartCallback.onSuccess(TaskRestartCallback.scala:72)
at monix.eval.internal.TaskRunLoop$.startFull(TaskRunLoop.scala:183)
at monix.eval.internal.TaskRestartCallback.syncOnSuccess(TaskRestartCallback.scala:101)
at monix.eval.internal.TaskRestartCallback.onSuccess(TaskRestartCallback.scala:74)
at monix.eval.internal.TaskSleep$SleepRunnable.run(TaskSleep.scala:71)
at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Running Task
isolates Local
, which was not available in the Future
, resulting in runToFuture
.
This release enables it and unblocks compelling use cases, such as reading proper request context in Akka HTTP Directive.
We've created an AkkaHTTP Example that demonstrates it.
Latest behavior is:
implicit val s: Scheduler = Scheduler.Implicits.traced
val local = Local(0)
for {
_ <- Task(local.update(1)).runToFuture
value <- Future(local.get)
} yield println(s"Local value in Future $value")
println(s"Local value on the current thread = $value")
// => Local value on the current thread = 0
// => Local value in Future = 1
Task
still isolates the Local
, but the Future
continuation keeps the same reference and can read it.
Before the change, Local
would be 0
in the Future
.
More information about Local
can be found in the new Local documentation.
The release is binary and source compatible with 3.x.x line. It is released for the following Scala and ScalaJS versions:
Relevant updates:
People who made this release possible:
The release is binary and source compatible with 3.x.x line. It is released for the following Scala and ScalaJS versions:
Relevant updates:
People that made this release possible:
The release is binary and source compatible with 3.0.0.
Important updates:
People that made this release possible:
This is the final release of Monix 3.0.0.
Important updates:
Chores:
People that made this release possible:
This is a bug fix release — fixing a critical issue:
NullPointerException
in Task
when used in combination with Local
InterceptableRunnable
exposed accidentally, refactor it for efficiencyThis release is binary compatible with 3.0.0-RC4
.
Last release before 3.0.0
which will be released as soon as Cats-Effect 2.0.0 is available. At the time of writing release notes, it is only waiting on Cats 2.0.0 which is about to release next RC which will become stable version if no critical issues are discovered.
Any other development for this release is now frozen except if we discover critical bugs like memory leaks. All other changes will target 3.1.0
.
3.0.0
will be binary and source compatible with 3.0.0-RC4
for Scala 2.12. Monix itself will be also binary compatible for 2.11 but it will have a dependency on Cats-Effect which is not. See Cats-Effect release notes for more details.
We wish we could release 3.0.0
already but if we released now, we would have to release 4.0.0
for Cats-Effect 2.0 because of 2.11 incompatibility there so we decided to hold on.
It was a rough road but currently we have multiple active maintainers that can do releases going forward, instead of just Alex so we hope it can give you a confidence for the future! :)
Note that Cats-Effect 2.0 is very small release and mostly targeted at support for Scala 2.13 and bug fixes - the upgrade should be limited to bumping version without changing a single line of code.
This release depends on Cats-Effect 1.4.0 and Cats 1.6.1
This release is binary compatible with 3.0.0-RC3
on Scala 2.12.
On Scala 2.11 there is an incompatibility caused by introduction of Scheduler.features
:
exclude[ReversedMissingMethodProblem]("monix.execution.Scheduler.features")
There are several fixes related to Local
usage.
TracingScheduler
will also automatically enable local context propagation in Task
so
running it with runToFutureOpt
or setting env variable is no longer a necessity.Local.isolate
has a overload for isolating Future
which is safer than regular Local.isolate
.The Local
model since 3.0.0-RC3
shares by default. To isolate modifications of Local
by
other concurrently running Future
, you have to call Local.isolate
.
In case of Task
, there is a TaskLocal.isolate
version. It is automatically called whenever you run Task
so if your use case is setting correlationId
or similar, it probably won't require any explicit isolation because
your HTTP library will most likely run the Task
per request.
There are two major improvements:
Task
builders (Task.create
, Task.async
, Task.fromFuture
etc.) will return a Task
that continues on default Scheduler
which is the one supplied during execution unless overriden by executeOn
.Task.create
is now thread-safe against contract violation (calling it more than once) so does not require synchronization on the user side.PR #946: Expose less implementation details in Local
PR #948: Make Task.memoize play well with Local
PR #953: Make default scheduler remove cancelled tasks
PR #960: Scheduler.features
PR #971: Callback tryOnSuccess/tryOnFailure
PR #973: Fix Local.isolate corner case
PR #977: Use type classes instead of overloads in Local.isolate/bind
PR #913: Optimize Task.guarantee
PR #921 & PR #917: Callbacks in Task.create are now thread-safe and always return to the main Scheduler.
PR #933: Adds >> syntax to Task
PR #935: Adds >> syntax to Coeval
PR #934: Implement doOnFinish in terms of guaranteeCase
PR #951: Add void to Task + Coeval
PR #952: Implement ContextShift.evalOn in terms of Task.executeOn
PR #954: Add gatherN + wanderN
PR #972: Rename Task.forkAndForget
to Task.startAndForget
PR #906: Fix race in MapParallelOrderedObservable
PR #918: switchMap should wait for last child to complete
PR #919: propagate cancellation to tasks in async Consumers
PR #932: Remove try-catch for EvalOnceObservable implementation
PR #941: Added some polymorphic methods for Observable
PR #945: Add collectWhile observable
PR #958: Add Observable.throttle
PR #963: Added fromAsyncStateActionF
PR #970: Observable.unfold
PR #989: Observable.unfoldEval and Observable.unfoldEvalF
PR #936: Add defaults values for benchmarking
Tons of updates by https://github.com/fthomas/scala-steward
People that made this release possible, in alphabetical order: