runtime start stop times for zio effects
Sometimes you need to collect the start and stop times for an effect running. For example, if the effect represents a job, you may want to record the job start and stop times in a database for analysis.
zio has a .timed
combinator that provides you a duration, but if you need to also add the start and stop time, .timed
is not quiet right.
Fortunately, we can add a few zip’ish combinators and get what we need. I use scala.js js.Date
in the code below but substitute in your own date function as appropriate:
/** Capture run stats including start and stop datetime. Once you have used the
* timing result via `flatMap{ case (start,stop,delta,exit) => ... }`, use
* `ZIO.done(exit)` to push the exit value back into an effect if desired.
*/
def timeRun[R, E,A](effect: ZIO[R,E,A]):
ZIO[R with zio.clock.Clock, Nothing, (js.Date, js.Date, zio.duration.Duration, Exit[E,A])] =
(UIO.succeed(new js.Date()) &&& effect.run).timed.map {
case (duration, (start, exit)) =>
val completed = new js.Date(start.getTime() + duration.toMillis)
(start, completed, duration, exit)
}
The .run
combinator gives you the exit value of the effect parameter so you can decide how to work with the result and date data. The &&&
combinator zips the results of each effect together and .timed
passes along the tuple (duration, effect result)
.
timeRun(effect){ case (start, stop, duration, exit) =>
val recordRunEffect = exit match {
case Exit.Success(v) => putStrLen(s"Success: start: $start, $stop, result: $v")
case Exit.Failure(c) => putStrLen(s"Failure: ${duration}ms: ${c.prettyPrint}")
}
// If desired, pass through the exit value as if this stage never happened!
recordRunEffect *> ZIO.done(exit)
}
It’s not a perfect approach though in case your date function takes a long time to run relative to the effect, but its probably good enough for many scenarios.
That’s it!
Comments
Post a Comment