Monix: Version 2.2.2 Released
Version 2.2.2 is out now.
It is a minor release that’s binary and source compatible with 2.2.x.
In summary:
- Implemented a circuit breaker for 
Task, for providing stability and preventing cascading failures in distributed systems - Added 
Task!.memoizeOnSuccessandCoeval!.memoizeOnSuccessoperators that only caches the result (with idempotency guarantees) for successful results, while re-evaluating the source on failures - Added 
Task.deferFutureActionthat helps with wrappingFuture-enabled APIs without requiringExecutionContextin the function signature, sinceTaskcan inject it for you - Added 
SingleAssignmentCancelable.plusOnefor helping with buildingConsumerobjects - Moved and redesigned exceptions in 
monix.execution Task.sequencenow has lazy behavior in evaluating the given sequence (previously we were doing afoldLefton that sequence, which could have strict behavior, depending on the collection type)- Critical bugs fixed!
 
Details below!
New Features #
Issue #306 -
Introduced a circuit breaker in monix.eval.TaskCircuitBreaker,
see documentation:
A circuit breaker is used to provide stability and prevent cascading failures in distributed systems:
import monix.eval._
import scala.concurrent.duration._
val circuitBreaker = TaskCircuitBreaker(
  maxFailures = 5,
  resetTimeout = 10.seconds
)
circuitBreaker.protect(problematicTask.timeout(1.second))
Issue #312 -
Introduced the Task!.memoizeOnSuccess operator, 
see documentation:
This Task!.memoizeOnSuccess operator, caches the result (with
idempotency guarantees), just like the normal memoize operator, only
it does so only on a successful result, whereas if failures happens,
subsequent calls will retry evaluating the source until it succeeds:
var effect = 0
val source = Task.eval { 
  effect += 1
  if (effect < 3) throw new RuntimeException("dummy") 
  else effect
}
val cached = source.memoizeOnSuccess
val f1 = cached.runAsync // yields RuntimeException
val f2 = cached.runAsync // yields RuntimeException
val f3 = cached.runAsync // yields 3
val f4 = cached.runAsync // yields 3
Issue #313 - 
On Task we added the deferFutureAction builder,
see documentation:
This helps with wrapping Future-enabled APIs, by being able to
specify a callback with an injected Scheduler:
def sumFuture(list: Seq[Int])(implicit ec: ExecutionContext): Future[Int] =
  Future(list.sum)
// Look Ma, no implicit ExecutionContext!
def sumTask(list: Seq[Int]): Task[Int] =
  Task.deferFutureAction { implicit scheduler =>
    sumFuture(list)
  }
Issue #325:
Added SingleAssignmentCancelable.plusOne builder,
see documentation:
This plusOne function builds a SingleAssignmentCancelable
reference which also cancels an extra cancelable specified at
construction time, in addition to the underlying cancelable that gets
assigned later:
val c = {
  val guest = Cancelable(() => println("extra canceled"))
  SingleAssignmentCancelable.plusOne(guest)
}
c := Cancelable(() => println("primary canceled"))
c.cancel()
//=> extra canceled
//=> primary canceled
This helps with building Consumer objects that need to specify a 
cancelable that cancels the data source, plus whatever resources
the consumer itself has opened.
List of Changes #
New Features and Enhancements:
- Issue #306:
Circuit Breaker for 
Task - Issue #312:
Add 
Task.memoizeOnSuccessandCoeval.memoizeOnSuccess - Issue #313:
Add 
Task.deferFutureActionbuilder - Issue #325:
Add 
SingleAssignmentCancelable.plusOne - Issue #319:
Move and redesign exceptions in 
monix.execution - Issue #314:
Task.sequenceshould have lazy behavior in evaluating the given sequence 
Bug fixes:
- Bug #268:
Optimise the unsubscribe logic in 
PublishSubject - Bug #308:
Fix NPE on 
AsyncSubject.unsubscribe - Bug #315:
The 
MapTaskObservableinternal object is exposed (ScalaDoc) - Bug #321:
Observable.concatMapandmapTaskcannot be canceled if the source has already completed - Documentation fixes: #307, #309, #311, #316 and #317
 
Build:
- enabled the Scala 
Migration Manager 
(MiMa) in 
build.sbtto check for backwards compatibility problems - Issue #322:
Switch projects which use 
CrossVersion.full/"org.scala-lang"toCrossVersion.patch/scalaOrganization.value 
Upgrading #
To use the new version, include this in your build.sbt (and use
%%% for Scala.js):
libraryDependencies += "io.monix" %% "monix" % "2.2.2"
The other projects from the @Monix organization have also been upgraded to depend on this new version.
shade, the Scala Memcached client:
dependencies += "io.monix" %% "shade" % "1.9.2"
monix-kafka, the Apache Kafka integration:
// For Kafka 8
libraryDependencies += "io.monix" %% "monix-kafka-8" % "0.11"
// For Kafka 9
libraryDependencies += "io.monix" %% "monix-kafka-9" % "0.11"
// For Kafka 10
libraryDependencies += "io.monix" %% "monix-kafka-10" % "0.11"
Enjoy!