Skip to content

Instantly share code, notes, and snippets.

@afsalthaj
Last active March 13, 2019 00:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save afsalthaj/8ef6a4fe2a0c1ad2e9beedd459c0df15 to your computer and use it in GitHub Desktop.
Save afsalthaj/8ef6a4fe2a0c1ad2e9beedd459c0df15 to your computer and use it in GitHub Desktop.
// http://degoes.net/articles/zio-challenge
// This is a quick try with Ref and I will keep trying!
import scalaz.zio.{UIO, ZIO, _}
final case class Percentage(value: Double) extends AnyVal
/**
* A `Tap` adjusts the flow of tasks through
* an external service in response to observed
* failures in the service, always trying to
* maximize flow while attempting to meet the
* user-defined upper bound on failures.
*/
trait Tap[-E1, +E2] {
/**
* Sends the task through the tap. The
* returned task may fail immediately with a
* default error depending on the service
* being guarded by the tap.
*/
def apply[R, E >: E2 <: E1, A](effect: ZIO[R, E, A]): ZIO[R, E, A]
}
object Tap {
/**
* Creates a tap that aims for the specified
* maximum error rate, using the specified
* function to qualify errors (unqualified
* errors are not treated as failures for
* purposes of the tap), and the specified
* default error used for rejecting tasks
* submitted to the tap.
*/
def make[E1, E2](
errBound: Percentage,
qualified: E1 => Boolean,
rejected: => E2
): UIO[Tap[E1, E2]] =
// or Queue ??
Ref.make[List[Boolean]](Nil).map(r =>
new Tap[E1, E2] {
override def apply[R, E >: E2 <: E1, A](effect: ZIO[R, E, A]): ZIO[R, E, A] =
for {
v <- r.get
a <-
if (v.count(!_) <= errBound.value * v.size) {
effect
.either
.flatMap(
_.fold(
e => r.update(addToList(qualified(e))).map(_ => Left[E, A](e)),
a => r.update(addToList(true)).map(_ => Right[E, A](a))
)
).absolve
} else {
r.update(addToList(true)) *> ZIO.fail(rejected)
}
} yield a
})
private def addToList[A](a: A): List[A] => List[A] =
a :: _.take(10)
}
@afsalthaj
Copy link
Author

afsalthaj commented Mar 12, 2019

When we do;

for {
 tap <- Tap.make(...)
 _ <- tap(computation1).zipPar(tap(computation2)).zipPar(tap(computation3))
} yield ()

that would mean, if all of them fails it does make > errorPercentage all of a sudden. However it starts rejecting and make the ratio back on track in future (for new requests)

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