anyway, my bracket looks like this
override def bracketCase[A, B](acquire: DBIO[A])(
use: A => DBIO[B]
)(release: (A, ExitCase[Throwable]) => DBIO[Unit]): DBIO[B] = {
acquire.flatMap { a =>
rethrow {
flatTap(attempt(use(a))) {
case Right(_) => release(a, ExitCase.complete)
case Left(e) => release(a, ExitCase.error(e))
}
}
}
}
if you ask why I'm not using syntax, I'll answer because it's 1am and I have a pretty dirty file with all this
override def async[A](
k: (Either[Throwable, A] => Unit) => Unit
): DBIO[A] = suspend {
val promise = Promise[A]()
k {
case Right(a) => promise.success(a)
case Left(t) => promise.failure(t)
}
DBIO.from(promise.future)
}
ThreadLocal
for storing a correlationId
. This is useful for scoping log entries (via MDC). This was however bound to Monix, is there such a thing for cats-effect IO
?
ThreadLocal
, but TaskLocal
: there are (possibly many) more Task/IO
running on one thread
Kleisli
would have a penalty in terms of performance right?
TaskLocal
(although not as big I will imagine)
Id
implicitly but putting it behind a Correlation[F]
algebraContextShift
to propagate the right MDC context as seen in http://code.hootsuite.com/logging-contextual-info-in-an-asynchronous-scala-application/
@Fristi in Monix you can use a TracingScheduler
, out of which you can build the proper ContextShift
, for IO
too, however it gets tricky — and the reason for why the logic for Monix's TaskLocal
resides in the Task run-loop itself.
For instance all it takes to screw your locals is something like this and your special ContextSwitch
won't help 😉
IO.async { cb =>
new Thread(() -> cb(Right(()))).start()
}
Task
protects against this of course, by restoring the original locals after such async tasks are done executing.
ContextSwitch
out of a Monix TrackingScheduler
and you can use the low-level Local
in monix-execution
, so you could do something with IO
, but you have to keep in mind the above gotcha.
ApplicativeAsk
for something like that (from cats-mtl)
def defaultContextShift[F[_]: Async](implicit ec: ExecutionContext): ContextShift[F] = new ContextShift[F] {
def shift: F[Unit] = Async.shift(ec)
def evalOn[A](ec: ExecutionContext)(fa: F[A]): F[A] =
Async[F].bracket(Async.shift(ec))(_ => fa)(_ => shift)
}
defaultContextShift
anywhere. If you need ContextShift[F]
, then get it as a function parameter.