A TaskLocal is like a
ThreadLocal
that is pure and with a flexible scope, being processed in the
context of the Task data type.
This data type wraps monix.execution.misc.Local.
Just like a ThreadLocal, usage of a TaskLocal is safe,
the state of all current locals being transported over
async boundaries (aka when threads get forked) by the Task
run-loop implementation, but only when the Task reference
gets executed with Task.Options.localContextPropagation
set to true, or it uses a monix.execution.schedulers.TracingScheduler.
One way to achieve this is with Task.executeWithOptions,
a single call is sufficient just before runToFuture:
{
import monix.execution.Scheduler.Implicits.global
val t = Task(42)
t.executeWithOptions(_.enableLocalContextPropagation)
// triggers the actual execution
.runToFuture
}
Another possibility is to use Task.runToFutureOpt
instead of runToFuture and specify the set of
options implicitly:
{
import monix.execution.Scheduler.Implicits.global
implicit val options: Task.Options = Task.defaultOptions.enableLocalContextPropagation
val t = Task(42)
// Options passed implicitly
val f = t.runToFutureOpt
}
Full example:
import monix.eval.{Task, TaskLocal}
val task: Task[Unit] =
for {
local <- TaskLocal(0)
value1 <- local.read // value1 == 0
_ <- local.write(100)
value2 <- local.read // value2 == 100
value3 <- local.bind(200)(local.read.map(_ * 2)) // value3 == 200 * 2
value4 <- local.read // value4 == 100
_ <- local.clear
value5 <- local.read // value5 == 0
} yield {
// Should print 0, 100, 400, 100, 0
println("value1: " + value1)
println("value2: " + value2)
println("value3: " + value3)
println("value4: " + value4)
println("value5: " + value5)
}
// For transporting locals over async boundaries defined by
// Task, any Scheduler will do, however for transporting locals
// over async boundaries managed by Future and others, you need
// a `TracingScheduler` here:
import monix.execution.Scheduler.Implicits.traced
// Triggering actual execution,
// runToFutureOpt is not needed if `TracingScheduler` is used
val result = task.runToFuture
- Companion:
- object
Value members
Concrete methods
Binds the local var to a value for the duration of the given
task execution.
Binds the local var to a value for the duration of the given
task execution.
// Should yield 200 on execution, regardless of what value
// we have in `local` at the time of evaluation
val task: Task[Int] =
for {
local <- TaskLocal(0)
value <- local.bind(100)(local.read.map(_ * 2))
} yield value
- Value parameters:
- See also:
bindL for the version with a lazy
value.
Clears the local var to the default for the duration of the
given task execution.
Clears the local var to the default for the duration of the
given task execution.
// Should yield 0 on execution, regardless of what value
// we have in `local` at the time of evaluation
val task: Task[Int] =
for {
local <- TaskLocal(0)
value <- local.bindClear(local.read.map(_ * 2))
} yield value
Binds the local var to a value for the duration of the given
task execution, the value itself being lazily evaluated
in the Task context.
Binds the local var to a value for the duration of the given
task execution, the value itself being lazily evaluated
in the Task context.
// Should yield 200 on execution, regardless of what value
// we have in `local` at the time of evaluation
val task: Task[Int] =
for {
local <- TaskLocal(0)
value <- local.bindL(Task.eval(100))(local.read.map(_ * 2))
} yield value
- Value parameters:
- See also:
bind for the version with a strict
value.
Clears the local value, making it return its default.
Clears the local value, making it return its default.
Returns monix.execution.misc.Local instance used in this TaskLocal.
Returns monix.execution.misc.Local instance used in this TaskLocal.
Note that TaskLocal.bind will restore the original local value
on the thread where the Task's run-loop ends up so it might lead
to leaving local modified in other thread.