An AsyncScheduler
schedules tasks to happen in the future with the
given ScheduledExecutorService
and the tasks themselves are executed on
the given ExecutionContext
.
Adds trampoline execution capabilities to schedulers, when inherited.
Marker for blocking operations that need to be disallowed on top of JavaScript engines, or other platforms that don't support the blocking of threads.
Marker for blocking operations that need to be disallowed on top of JavaScript engines, or other platforms that don't support the blocking of threads.
As sample, lets implement a low-level blocking operation; but kids,
don't do this at home, since this is error prone and you already have
Scala's Await.result
, this sample being shown for pedagogical purposes:
import monix.execution.schedulers.CanBlock import java.util.concurrent.CountDownLatch import scala.concurrent.{ExecutionContext, Future} import scala.util.Try def block[A](fa: Future[A]) (implicit ec: ExecutionContext, permit: CanBlock): Try[A] = { var result = Option.empty[Try[A]] val latch = new CountDownLatch(1) fa.onComplete { r => result = r latch.countDown() } latch.await() result.get }
And then for JavaScript engines (Scala.js) you could describe the same function, with the same signature, but without any implementation, since this operation isn't supported:
def block[A](fa: Future[A]) (implicit ec: ExecutionContext, permit: CanBlock): Try[A] = throw new UnsupportedOperationException("Cannot block threads on top of JavaScript")
Now in usage, when the caller is invoking block
as described, it will
work without issues on top of the JVM, but when compiled with Scala.js
it will trigger a message like this:
[error] Playground.scala:30:8: Blocking operations aren't supported [error] on top of JavaScript, because it cannot block threads! [error] Please use asynchronous API calls. [error] block(Future(1)) [error] ^
An ExecutorScheduler is a class for building a
SchedulerService
out of a Java ExecutorService
.
Helper for building a Scheduler.
Helper for building a Scheduler.
You can inherit from this class and provided a correct scheduleOnce you'll get Scheduler.scheduleWithFixedDelay and Scheduler.scheduleAtFixedRate for free.
A Scheduler type that provides methods for managing termination.
A Scheduler type that provides methods for managing termination.
A SchedulerService
can be shut down, which will cause it to reject
new tasks. The shutdown
method allows previously submitted tasks to
execute before terminating. The awaitTermination
method allows
waiting on all active tasks to finish.
Upon termination, an executor has no tasks actively executing, no tasks
awaiting execution, and no new tasks can be submitted. An unused
SchedulerService
should be shut down to allow reclamation of
its resources.
Runnable that defers the execution of the given reference
with an executeAsync
.
Runnable that defers the execution of the given reference
with an executeAsync
.
This is useful for example when implementing scheduleOnce
,
to introduce a boundary between the scheduling and the execution,
otherwise risk executing the runnable on the wrong thread-pool.
Forces a real asynchronous boundary before executing the given TrampolinedRunnable.
Forces a real asynchronous boundary before executing the given TrampolinedRunnable.
Sometimes you want to execute multiple TrampolinedRunnable instances as a batch, with the functionality provided by schedulers implementing BatchingScheduler, however you might need the very first execution to force an asynchronous boundary.
is the TrampolinedRunnable instance that will get executed and that is supposed to trigger the execution of other trampolined runnables
is the scheduler that gets used for execution.
Scheduler and a provider of cats.effect.Timer
instances,
that can simulate async boundaries and time passage, useful for
testing purposes.
Scheduler and a provider of cats.effect.Timer
instances,
that can simulate async boundaries and time passage, useful for
testing purposes.
Usage for simulating an ExecutionContext
:
implicit val ec = TestScheduler() ec.execute(new Runnable { def run() = println("task1") }) ex.execute(new Runnable { def run() = { println("outer") ec.execute(new Runnable { def run() = println("inner") }) } }) // Nothing executes until `tick` gets called ec.tick() // Testing the resulting state assert(ec.state.tasks.isEmpty) assert(ec.state.lastReportedError == null)
TestScheduler
can also simulate the passage of time:
val ctx = TestScheduler() val f = Task(1 + 1).delayExecution(10.seconds).runAsync // This only triggers immediate execution, so nothing happens yet ctx.tick() assert(f.value == None) // Simulating the passage of 5 seconds, nothing happens yet ctx.tick(5.seconds) assert(f.value == None) // Simulating another 5 seconds, now we're done! assert(f.value == Some(Success(2)))
We are also able to build a cats.effect.Timer
from any Scheduler
and for any data type:
val ctx = TestScheduler() val timer: Timer[IO] = ctx.timer[IO]
We can now simulate time passage for cats.effect.IO
as well:
val io = timer.sleep(10.seconds) *> IO(1 + 1) val f = io.unsafeToFuture() // This invariant holds true, because our IO is async assert(f.value == None) // Not yet completed, because this does not simulate time passing: ctx.tick() assert(f.value == None) // Simulating time passing: ctx.tick(10.seconds) assert(f.value == Some(Success(2))
Simulating time makes this pretty useful for testing race conditions:
val timeoutError = new TimeoutException val timeout = Task.raiseError[Int](timeoutError) .delayExecution(10.seconds) val pair = (Task.never, timeout).parMapN(_ + _) // Not yet ctx.tick() assert(f.value == None) // Not yet ctx.tick(5.seconds) assert(f.value == None) // Good to go: ctx.tick(5.seconds) assert(f.value == Some(Failure(timeoutError)))
Wraps a Runnable
into one that restores the given
Local.Context
upon execution of run()
.
Wraps a Runnable
into one that restores the given
Local.Context
upon execution of run()
.
Used by TracingScheduler.
The TracingScheduler
is a Scheduler
implementation that wraps another Scheduler
reference, but
that propagates the Local.Context
on async execution.
The TracingScheduler
is a Scheduler
implementation that wraps another
SchedulerService
reference, with the purpose of propagating the
Local.Context on async
execution.
A scala.concurrentExecutionContext
implementation
that executes runnables immediately, on the current thread,
by means of a trampoline implementation.
A scala.concurrentExecutionContext
implementation
that executes runnables immediately, on the current thread,
by means of a trampoline implementation.
Can be used in some cases to keep the asynchronous execution on the current thread, as an optimization, but be warned, you have to know what you're doing.
The TrampolineExecutionContext
keeps a reference to another
underlying
context, to which it defers for:
Deferring the rest of the queue happens:
underlying
contextblocking
context, the rest of the tasks get re-scheduled for execution
on the underlying
context to prevent any deadlocksThus this implementation is compatible with the
scala.concurrent.BlockContext
, detecting blocking
blocks and
reacting by forking the rest of the queue to prevent deadlocks.
A Scheduler implementation that executes runnables immediately, on the current thread, by means of a trampoline implementation.
A Scheduler implementation that executes runnables immediately, on the current thread, by means of a trampoline implementation.
Can be used in some cases to keep the asynchronous execution on the current thread, as an optimization, but be warned, you have to know what you're doing.
The TrampolineScheduler
keeps a reference to another
underlying
scheduler, to which it defers for:
Deferring the rest of the queue happens:
underlying
schedulerblocking
context, the rest of the tasks get re-scheduled for execution
on the underlying
scheduler to prevent any deadlocksThus this implementation is compatible with the
scala.concurrent.BlockContext
, detecting blocking
blocks and
reacting by forking the rest of the queue to prevent deadlocks.
A marker for callbacks that can be batched and executed locally (on the current thread) by means of a trampoline (if the execution context / scheduler allows it).
A marker for callbacks that can be batched and executed locally (on the current thread) by means of a trampoline (if the execution context / scheduler allows it).
Idea was taken from the scala.concurrent.Future
implementation. Credit should be given where due.
DO NOT use unless you know what you're doing.
Adds trampoline execution capabilities to schedulers, when inherited.
When it receives TrampolinedRunnable instances, it switches to a trampolined mode where all incoming TrampolinedRunnable are executed on the current thread.
This is useful for light-weight callbacks. The idea is borrowed from the implementation of
scala.concurrent.Future
. Currently used as an optimization byTask
in processing its internal callbacks.