Skip to content

Instantly share code, notes, and snippets.

@danilbykov
Last active October 11, 2019 12:15
Show Gist options
  • Save danilbykov/957487c9463a66daa69290698a9320ac to your computer and use it in GitHub Desktop.
Save danilbykov/957487c9463a66daa69290698a9320ac to your computer and use it in GitHub Desktop.
import cats.effect.ExitCase._
import cats.effect.Sync
import cats.effect.concurrent.Ref
import cats.syntax.flatMap._
import cats.syntax.functor._
trait Tap[F[_]] {
def apply[A](effect: F[A]): F[A]
}
object Tap {
type Percentage = Double
def make[F[_]: Sync](errBound: Percentage,
qualified: Throwable => Boolean,
rejected: => Throwable): F[Tap[F]] = {
for {
ref <- Ref.of[F, TapState](TapState(Nil))
} yield new TapImpl(ref, errBound, qualified, rejected)
}
val tailSize = 100
private case class TapState(lastResults: List[Boolean])
private final class TapImpl[F[_]: Sync](ref: Ref[F, TapState],
errBound: Percentage,
qualified: Throwable => Boolean,
rejected: => Throwable) extends Tap[F] {
override def apply[A](effect: F[A]): F[A] =
for {
state <- ref.get
failed = state.lastResults.count(_ == false)
result <-
if (failed <= state.lastResults.size * errBound) {
Sync[F].guaranteeCase(effect) {
case Completed =>
ref.update(updateState(true))
case Error(e) =>
ref.update(updateState(qualified(e)))
case Canceled =>
Sync[F].unit
}
} else {
ref.update(updateState(true)) >> Sync[F].raiseError(rejected)
}
} yield result
private def updateState(newResult: Boolean)(state: TapState): TapState =
state.copy(lastResults = (newResult :: state.lastResults).take(tailSize))
}
}
@danilbykov
Copy link
Author

danilbykov commented Mar 16, 2019

Let's assume that every second request fails on our service so we get series of true, false, true, false and so on. We feed these results into ErrorStats(100):

(1 to 100).foldLeft(ErrorStats(100)) {
  case (stat, _) => stat.update(true).update(false)
} rate

Final rate is 0.01 which is too good where only half of requests is successful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment