Skip to content

Commit

Permalink
Merge pull request #13 from davenverse/simplifyHttp4s
Browse files Browse the repository at this point in the history
Simplify Http4s Interfaces
  • Loading branch information
ChristopherDavenport authored May 31, 2022
2 parents f7dc1d3 + e15bfeb commit 5040a9e
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 14 deletions.
17 changes: 15 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,27 @@ lazy val core = crossProject(JVMPlatform, JSPlatform)
libraryDependencies += "com.github.jnr" % "jnr-unixsocket" % "0.38.15" % Test,
)

lazy val http4s = crossProject(JVMPlatform, JSPlatform)
.crossType(CrossType.Pure)
.in(file("http4s"))
.dependsOn(core)
.settings(yPartial)
.settings(yKindProjector)
.settings(
name := "rediculous-concurrent-http4s",
libraryDependencies ++= Seq(
"io.chrisdavenport" %% "circuit-http4s-client" % "0.4.0",
)
)


lazy val examples = project.in(file("examples"))
.disablePlugins(MimaPlugin)
.dependsOn(core.jvm)
.dependsOn(core.jvm, http4s.jvm)
.settings(
publish / skip := true,
name := "rediculous-examples",
libraryDependencies ++= Seq(
"io.chrisdavenport" %% "circuit-http4s-client" % "0.4.0",
"org.http4s" %% "http4s-ember-client" % "0.23.12"
)
)
Expand Down
14 changes: 2 additions & 12 deletions examples/src/main/scala/HttpCircuiting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,15 @@ import com.comcast.ip4s._
import _root_.io.chrisdavenport.mapref.MapRef
import org.http4s.client.RequestKey
import org.http4s.ember.client.EmberClientBuilder
import _root_.io.chrisdavenport.circuit.http4s.client.CircuitedClient
import _root_.io.chrisdavenport.circuit.CircuitBreaker
import io.chrisdavenport.rediculous.concurrent.http4s.RedisCircuitedClient

object HttpCircuiting extends ResourceApp.Simple {

def run: Resource[IO, Unit] = for {
connection <- RedisConnection.queued[IO].withHost(host"localhost").withPort(port"6379").build
baseState = RedisCircuit.keyCircuitState(connection, 10.seconds, 10.seconds, RedisCommands.SetOpts.default.copy(setSeconds = 120L.some))
state = contramapKeys[IO, String, RequestKey, Option[CircuitBreaker.State]](baseState)(requestKey(_))
automaticallyCircuitedClient <- EmberClientBuilder.default[IO].build
.map(CircuitedClient.byMapRefAndKeyed(state, RequestKey.fromRequest(_), maxFailures = 50, 1.second))
.map(RedisCircuitedClient(connection)(_))
} yield ()

def requestKey(requestKey: RequestKey, prefix: String = "http4s-circuit-"): String = {
prefix ++ requestKey.toString
}

def contramapKeys[F[_], K1, K2, V](mapRef: MapRef[F, K1, V])(g: K2 => K1): MapRef[F, K2, V] =
new MapRef[F, K2, V]{
def apply(k: K2): Ref[F, V] = mapRef(g(k))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package io.chrisdavenport.rediculous.concurrent.http4s


import cats.syntax.all._
import cats.effect.kernel._
import io.chrisdavenport.mapref.MapRef
import org.http4s.client._
import scala.concurrent.duration._
import io.chrisdavenport.rediculous._
import io.chrisdavenport.circuit.Backoff
import io.chrisdavenport.rediculous.concurrent.RedisCircuit
import io.chrisdavenport.circuit.http4s.client.CircuitedClient
import org.http4s._
import io.chrisdavenport.circuit.CircuitBreaker
import io.chrisdavenport.circuit.CircuitBreaker.RejectedExecution
import io.chrisdavenport.circuit.http4s.client.CircuitedClient._

object RedisCircuitedClient {

def apply[F[_]: Async](
redisConnection: RedisConnection[F],
circuitMaxFailures: Int = 50,
circuitResetTimeout: FiniteDuration = 1.second,
redisSetOpts: RedisCommands.SetOpts = RedisCommands.SetOpts.default.copy(setSeconds = 120L.some),
redisAcquireTimeout: FiniteDuration = 5.seconds,
redisLockDuration: FiniteDuration = 10.seconds,
redisCircuitPrefix: String = "http4s-circuit-",
circuitBackoff: FiniteDuration => FiniteDuration = Backoff.exponential,
circuitMaxResetTimeout: Duration = 1.minute,
circuitModifications: CircuitBreaker[Resource[F, *]] => CircuitBreaker[Resource[F, *]] = {(x: CircuitBreaker[Resource[F, *]]) => x},
circuitTranslatedError: (Request[F], RejectedExecution, RequestKey) => Option[Throwable] = defaultTranslatedError[F, RequestKey](_, _, _),
circuitShouldFail: (Request[F], Response[F]) => ShouldCircuitBreakerSeeAsFailure = defaultShouldFail[F](_, _)
)(client: Client[F]): Client[F] = {
val iState = RedisCircuit.keyCircuitState(redisConnection, redisAcquireTimeout, redisLockDuration, redisSetOpts)
val state = contramapKeys(iState)(requestKey(_, redisCircuitPrefix))
CircuitedClient.byMapRefAndKeyed[F, RequestKey](
state,
RequestKey.fromRequest(_),
circuitMaxFailures,
circuitResetTimeout,
circuitBackoff,
circuitMaxResetTimeout,
circuitModifications,
circuitTranslatedError,
circuitShouldFail
)(client)
}


private def requestKey(requestKey: RequestKey, prefix: String = "http4s-circuit-"): String = {
prefix ++ requestKey.toString
}

private def contramapKeys[F[_], K1, K2, V](mapRef: MapRef[F, K1, V])(g: K2 => K1): MapRef[F, K2, V] =
new MapRef[F, K2, V]{
def apply(k: K2): Ref[F, V] = mapRef(g(k))
}
}

0 comments on commit 5040a9e

Please sign in to comment.