Callback
For the latest version: see here!
Callback
is a listener type that can be called asynchronously with
the result of a computation.
When building an asynchronous Task
, on execution the API gives you a
Callback
instance that you can invoke with the result of a
computation, on completion. Its definition is something like:
trait Callback[-T] extends (Try[T] => Unit) {
def onSuccess(value: T): Unit
def onError(ex: Throwable): Unit
}
This callback type has a contract:
- on completion, if it was a successful execution, one needs to call
onSuccess
- on completion, if the execution ended in error, one needs to call
onError
- after calling
onSuccess
oronError
then no more calls are allowed, as that would be a contract violation
In order to protect the contract, you can wrap any such callback into a “safe” implementation that protects against violations:
import monix.eval.Callback
val callback = new Callback[Int] {
def onSuccess(value: Int): Unit =
println(value)
def onError(ex: Throwable): Unit =
System.err.println(ex)
}
// We need an exception reporter, but we can just use a Scheduler
import monix.execution.Scheduler.Implicits.global
val safeCallback1 = Callback.safe(callback)
// But really, we don't need a Scheduler
import monix.execution.UncaughtExceptionReporter
import UncaughtExceptionReporter.{LogExceptionsToStandardErr => r}
val safeCallback2 = Callback.safe(callback)(r)
NOTE: when executing Task.runAsync(callback)
, the provided
callback is automatically wrapped in Callback.safe
, so you don’t
need to worry about it.
In case you just want an empty callback that doesn’t do anything
on onSuccess
, but that can log errors when onError
happens,
maybe because you just want the side-effects:
val task = monix.eval.Task(println("Sample"))
// task: monix.eval.Task[Unit] = FlatMap(
// Async(monix.eval.Task$$$Lambda$9215/0x0000000802e61040@3aa00e8d),
// monix.eval.Task$$$Lambda$9216/0x0000000802e80040@29ad3767
// )
task.runAsync(Callback.empty)
// res1: monix.execution.Cancelable = monix.execution.cancelables.StackedCancelable@649e7b07
Or maybe you want to convert a Scala Promise
to a Callback
:
val p = scala.concurrent.Promise[String]()
// p: concurrent.Promise[String] = Future(<not completed>)
val callback = Callback.fromPromise(p)
// callback: Callback[String] = <function1>
An interesting effect when dealing with callbacks is that callbacks
calling other callbacks can quickly and easily lead to stack-overflow
errors. So to force a protective asynchronous boundary when calling
onSuccess
or onError
(which may or may not fork a thread):
// Lets pretend we have something meaningful
val ref = Callback.empty[String]
val asyncCallback = Callback.async(ref)