Last active
October 11, 2019 12:15
-
-
Save danilbykov/957487c9463a66daa69290698a9320ac to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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)
:Final rate is 0.01 which is too good where only half of requests is successful.