Creates a simple, noncancelable F[A]
instance that
executes an asynchronous process on evaluation.
Creates a simple, noncancelable F[A]
instance that
executes an asynchronous process on evaluation.
The given function is being injected with a side-effectful callback for signaling the final result of an asynchronous process.
is a function that should be called with a callback for signaling the result once it is ready
A generalized version of bracket which uses ExitCase to distinguish between different exit cases when releasing the acquired resource.
A generalized version of bracket which uses ExitCase to distinguish between different exit cases when releasing the acquired resource.
is an action that "acquires" some expensive resource, that needs to be used and then discarded
is the action that uses the newly allocated resource and that will provide the final result
is the action that's supposed to release the
allocated resource after use
is done, by observing
and acting on its exit condition
Creates a cancelable F[A]
instance that executes an
asynchronous process on evaluation.
Creates a cancelable F[A]
instance that executes an
asynchronous process on evaluation.
This builder accepts a registration function that is being injected with a side-effectful callback, to be called when the asynchronous process is complete with a final result.
The registration function is also supposed to return
an IO[Unit]
that captures the logic necessary for
cancelling the asynchronous process, for as long as it
is still active.
Example:
import java.util.concurrent.ScheduledExecutorService import scala.concurrent.duration._ def sleep[F[_]](d: FiniteDuration) (implicit F: Concurrent[F], ec: ScheduledExecutorService): F[A] = { F.cancelable { cb => // Note the callback is pure, so we need to trigger evaluation val run = new Runnable { def run() = cb(Right(())).unsafeRunSync } // Schedules task to run after delay val future = ec.schedule(run, d.length, d.unit) // Cancellation logic, suspended in IO IO(future.cancel()) } }
Returns a new F
value that mirrors the source for normal
termination, but that triggers the given error on cancelation.
Returns a new F
value that mirrors the source for normal
termination, but that triggers the given error on cancelation.
This onCancelRaiseError
operator transforms any task into one
that on cancelation will terminate with the given error, thus
transforming potentially non-terminating tasks into ones that
yield a certain error.
import scala.concurrent.CancellationException val F = Concurrent[IO] val timer = Timer[IO] val error = new CancellationException("Boo!") val fa = F.onCancelRaiseError(timer.sleep(5.seconds, error)) fa.start.flatMap { fiber => fiber.cancel *> fiber.join }
Without "onCancelRaiseError" the sleep operation
yields a non-terminating task on cancellation. But by applying
"onCancelRaiseError", the yielded task above will terminate with
the indicated "CancellationException" reference, which we can
then also distinguish from other errors thrown in the F
context.
Depending on the implementation, tasks that are canceled can become non-terminating. This operation ensures that when cancelation happens, the resulting task is terminated with an error, such that logic can be scheduled to happen after cancelation:
import scala.concurrent.CancellationException val wasCanceled = new CancellationException() F.onCancelRaiseError(fa, wasCanceled).attempt.flatMap { case Right(a) => F.delay(println(s"Success: $a")) case Left(`wasCanceled`) => F.delay(println("Was canceled!")) case Left(error) => F.delay(println(s"Terminated in error: $error")) }
This technique is how a "bracket" operation can be implemented.
Besides sending the cancelation signal, this operation also cuts the connection between the producer and the consumer. Example:
val F = Concurrent[IO] val timer = Timer[IO] // This task is uninterruptible ;-) val tick = F.uncancelable( for { _ <- timer.sleep(5.seconds) _ <- IO(println("Tick!")) } yield ()) // Builds an value that triggers an exception on cancellation val loud = F.onCancelRaiseError(tick, new CancellationException)
In this example the loud
reference will be completed with a
"CancellationException", as indicated via "onCancelRaiseError".
The logic of the source won't get cancelled, because we've
embedded it all in uncancelable. But its bind continuation is
not allowed to continue after that, its final result not being
allowed to be signaled.
Therefore this also transforms uncancelable values into ones
that can be canceled. The logic of the source, its run-loop
might not be interruptible, however cancel
on a value on which
onCancelRaiseError
was applied will cut the connection from
the producer, the consumer receiving the indicated error instead.
Run two tasks concurrently, creating a race between them and returns a pair containing both the winner's successful value and the loser represented as a still-unfinished fiber.
Run two tasks concurrently, creating a race between them and returns a pair containing both the winner's successful value and the loser represented as a still-unfinished fiber.
If the first task completes in error, then the result will complete in error, the other task being cancelled.
On usage the user has the option of cancelling the losing task, this being equivalent with plain race:
val ioA: IO[A] = ??? val ioB: IO[B] = ??? Concurrent[IO].racePair(ioA, ioB).flatMap { case Left((a, fiberB)) => fiberB.cancel.map(_ => a) case Right((fiberA, b)) => fiberA.cancel.map(_ => b) }
See race for a simpler version that cancels the loser immediately.
Evaluates F[_]
, with the effect of starting the run-loop
being suspended in the IO
context.
Evaluates F[_]
, with the effect of starting the run-loop
being suspended in the IO
context.
Note that evaluating the returned IO[Unit]
is guaranteed
to execute immediately:
val io = F.runAsync(fa)(cb) // For triggering actual execution, guaranteed to be // immediate because it doesn't wait for the result io.unsafeRunSync
Evaluates F[_]
with the ability to cancel it.
Evaluates F[_]
with the ability to cancel it.
The returned IO[IO[Unit]]
is a suspended cancelable action that
can be used to cancel the running computation.
Note that evaluating the returned IO
value, along with
the boxed cancelable action are guaranteed to have immediate
(synchronous) execution so you can safely do this, even
on top of JavaScript (which has no ability to block threads):
val io = F.runCancelable(fa)(cb) // For triggering asynchronous execution val cancel = io.unsafeRunSync // For cancellation cancel.unsafeRunSync
Start concurrent execution of the source suspended in
the F
context.
Start concurrent execution of the source suspended in
the F
context.
Returns a Fiber that can be used to either join or cancel the running computation, being similar in spirit (but not in implementation) to starting a thread.
Suspends the evaluation of an F
reference.
Suspends the evaluation of an F
reference.
Equivalent to FlatMap.flatten
for pure expressions,
the purpose of this function is to suspend side effects
in F
.
Returns a new F
that mirrors the source, but that is uninterruptible.
Returns a new F
that mirrors the source, but that is uninterruptible.
This means that the cancel signal has no effect on the result of join and that the cancelable token returned by ConcurrentEffect.runCancelable on evaluation will have no effect.
This operation is undoing the cancelation mechanism of cancelable, with this equivalence:
F.uncancelable(F.cancelable { cb => f(cb); io }) <-> F.async(f)
Sample:
val F = Concurrent[IO] val timer = Timer[IO] // Normally Timer#sleep yields cancelable tasks val tick = F.uncancelable(timer.sleep(10.seconds)) // This prints "Tick!" after 10 seconds, even if we are // cancelling the Fiber after start: for { fiber <- F.start(tick) _ <- fiber.cancel _ <- fiber.join } yield { println("Tick!") }
Cancelable effects are great in race conditions, however sometimes
this operation is necessary to ensure that the bind continuation
of a task (the following flatMap
operations) are also evaluated
no matter what.
Operation meant for specifying tasks with safe resource acquisition and release in the face of errors and interruption.
Operation meant for specifying tasks with safe resource acquisition and release in the face of errors and interruption.
This operation provides the equivalent of try/catch/finally
statements in mainstream imperative languages for resource
acquisition and release.
is an action that "acquires" some expensive resource, that needs to be used and then discarded
is the action that uses the newly allocated resource and that will provide the final result
is the action that's supposed to release the
allocated resource after use
is done, irregardless of
its exit condition
Lifts any by-name parameter into the F
context.
Lifts any by-name parameter into the F
context.
Equivalent to Applicative.pure
for pure expressions,
the purpose of this function is to suspend side effects
in F
.
Inherited from LiftIO, defines a conversion from IO
in terms of the Concurrent
type class.
Inherited from LiftIO, defines a conversion from IO
in terms of the Concurrent
type class.
N.B. expressing this conversion in terms of Concurrent
and
its capabilities means that the resulting F
is cancelable in
case the source IO
is.
To access this implementation as a standalone function, you can use Concurrent.liftIO (on the object companion).
Returns a non-terminating F[_]
, that never completes
with a result, being equivalent to async(_ => ())
Returns a non-terminating F[_]
, that never completes
with a result, being equivalent to async(_ => ())
Run two tasks concurrently and return the first to finish, either in success or error.
Run two tasks concurrently and return the first to finish, either in success or error. The loser of the race is cancelled.
The two tasks are potentially executed in parallel, the winner being the first that signals a result.
As an example, this would be the implementation of a "timeout" operation:
import cats.effect._ import scala.concurrent.duration._ def timeoutTo[F[_], A](fa: F[A], after: FiniteDuration, fallback: F[A]) (implicit F: Concurrent[F], timer: Timer[F]): F[A] = { F.race(fa, timer.sleep(after)).flatMap { case Left((a, _)) => F.pure(a) case Right((_, _)) => fallback } } def timeout[F[_], A](fa: F[A], after: FiniteDuration) (implicit F: Concurrent[F], timer: Timer[F]): F[A] = { timeoutTo(fa, after, F.raiseError(new TimeoutException(after.toString))) }
Also see racePair for a version that does not cancel the loser automatically on successful results.
(Since version 1.0.0-RC2) Use *> or productR instead.
(Since version 1.0.0-RC2) Use productREval instead.
(Since version 1.0.0-RC2) Use <* or productL instead.
(Since version 1.0.0-RC2) Use productLEval instead.
Type class describing effect data types that are cancelable.
In addition to the algebras of Concurrent and of Effect, instances must also implement a runCancelable operation that triggers the evaluation, suspended in the
IO
context, but that also returns a token that can be used for cancelling the running computation.Note this is the safe and generic version of IO.unsafeRunCancelable.