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.