Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"migrate" to cats effect 3 #305

Merged
merged 4 commits into from
Apr 23, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ val moduleSettings = commonSettings ++ Seq(
scalafmtOnCompile := true
)

val catsVersion = "2.3.0"
val catsEffectVersion = "2.3.1"
val catsMtlVersion = "1.1.1"
val catsVersion = "2.5.0"
val catsEffectVersion = "3.0.2"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use 3.1.0 now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

version updated

val catsMtlVersion = "1.1.3"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.2.0 if you want to be on latest

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

version updated

val scalatestVersion = "3.2.3"
val scalaTestPlusVersion = "3.2.2.0"
val scalacheckVersion = "1.15.2"
Expand Down Expand Up @@ -134,7 +134,7 @@ val docs = project
"org.typelevel" %% "kind-projector" % "0.11.0" cross CrossVersion.full
),
libraryDependencies ++= Seq(
"io.monix" %%% "monix" % "3.1.0"
//"io.monix" %%% "monix" % "3.3.0" // TODO update to version compatible cats effect 3
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just drop it I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dropped

),
crossScalaVersions := Nil,
buildInfoPackage := "retry",
Expand Down
7 changes: 4 additions & 3 deletions modules/core/shared/src/main/scala/retry/Sleep.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package retry

import cats.effect.Timer
import cats.effect.Temporal

import scala.concurrent.duration.FiniteDuration

trait Sleep[M[_]] {
Expand All @@ -10,6 +11,6 @@ trait Sleep[M[_]] {
object Sleep {
def apply[M[_]](implicit sleep: Sleep[M]): Sleep[M] = sleep

implicit def sleepUsingTimer[F[_]](implicit timer: Timer[F]): Sleep[F] =
(delay: FiniteDuration) => timer.sleep(delay)
implicit def sleepUsingTemporal[F[_]](implicit t: Temporal[F]): Sleep[F] =
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm starting to think Sleep should just be replaced with Temporal altogether.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I see, replacing Sleep by Temporal has a bigger impact:
given that Temporal[F[_]] = GenTemporal[F, Throwable]

You end up with MonadError[F, Throwable] following the hierarchy GenTemporal[F, E] ... GenConcurrent[F, E] ... GenSpawn[F, E] ... MonadCancel[F, E] ... MonadError[F, E]

Then Temporal[F] will clash with internals based on MonadError[F, E], though it seems that GenTemporal[F, E] solves it but the change propagates up to public function.. not sure if that's desired.. I think it's probably better to try it in a separate PR

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, these are good points :)

(delay: FiniteDuration) => t.sleep(delay)
}
7 changes: 2 additions & 5 deletions modules/docs/src/main/mdoc/docs/combinators.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,11 @@ You need to pass in:
For example, let's keep rolling a die until we get a six, using `IO`.

```scala mdoc
import cats.effect.IO
import cats.effect.unsafe.implicits.global
import retry._

import cats.effect.{IO, Timer}
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.global

// We need an implicit cats.effect.Timer
implicit val timer: Timer[IO] = IO.timer(global)

val policy = RetryPolicies.constantDelay[IO](10.milliseconds)

Expand Down
6 changes: 1 addition & 5 deletions modules/docs/src/main/mdoc/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,7 @@ def logError(err: Throwable, details: RetryDetails): IO[Unit] = details match {

// Now we have a retry policy and an error handler, we can wrap our `IO` inretries.

// We need an implicit cats.effect.Timer
import cats.effect.Timer
import scala.concurrent.ExecutionContext.global
implicit val timer: Timer[IO] = IO.timer(global)

import cats.effect.unsafe.implicits.global

val flakyRequestWithRetry: IO[String] =
retryingOnAllErrors[String](
Expand Down
19 changes: 7 additions & 12 deletions modules/docs/src/main/mdoc/docs/mtl-combinators.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,10 @@ Example:
```scala mdoc
import retry.{RetryDetails, RetryPolicies}
import cats.data.EitherT
import cats.effect.{Sync, IO, Timer}
import cats.effect.{Sync, IO}
import cats.mtl.Handle
import scala.concurrent.duration._

// We need an implicit cats.effect.Timer
implicit val timer: Timer[IO] = IO.timer(scala.concurrent.ExecutionContext.global)
import cats.effect.unsafe.implicits.global

type Effect[A] = EitherT[IO, AppError, A]

Expand Down Expand Up @@ -120,12 +118,10 @@ Example:
```scala mdoc:reset
import retry.{RetryDetails, RetryPolicies}
import cats.data.EitherT
import cats.effect.{Sync, IO, Timer}
import cats.effect.{Sync, IO}
import cats.mtl.Handle
import scala.concurrent.duration._

// We need an implicit cats.effect.Timer
implicit val timer: Timer[IO] = IO.timer(scala.concurrent.ExecutionContext.global)
import cats.effect.unsafe.implicits.global

type Effect[A] = EitherT[IO, AppError, A]

Expand All @@ -152,17 +148,18 @@ Cats-retry-mtl include some syntactic sugar in order to reduce boilerplate.
```scala mdoc:reset
import retry._
import cats.data.EitherT
import cats.effect.{Sync, IO, Timer}
import cats.effect.{Sync, IO}
import cats.syntax.functor._
import cats.syntax.flatMap._
import cats.mtl.Handle
import retry.mtl.syntax.all._
import retry.syntax.all._
import scala.concurrent.duration._
import cats.effect.unsafe.implicits.global

case class AppError(reason: String)

class Service[F[_]: Timer](client: util.FlakyHttpClient)(implicit F: Sync[F], AH: Handle[F, AppError]) {
class Service[F[_]: Sleep](client: util.FlakyHttpClient)(implicit F: Sync[F], AH: Handle[F, AppError]) {

// evaluates retry exclusively on errors produced by Handle.
def findCoolCatGifRetryMtl(policy: RetryPolicy[F]): F[String] =
Expand Down Expand Up @@ -196,8 +193,6 @@ class Service[F[_]: Timer](client: util.FlakyHttpClient)(implicit F: Sync[F], AH

type Effect[A] = EitherT[IO, AppError, A]

implicit val timer: Timer[IO] = IO.timer(scala.concurrent.ExecutionContext.global)

val policy = RetryPolicies.limitRetries[Effect](5)

val service = new Service[Effect](util.FlakyHttpClient())
Expand Down
5 changes: 2 additions & 3 deletions modules/docs/src/main/mdoc/docs/policies.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,17 +151,16 @@ fibonacciBackoff[IO](200.millis).flatMapDelay { currentDelay =>
### mapK

If you've defined a `RetryPolicy[F]`, but you need a `RetryPolicy` for another effect type `G[_]`, you can use `mapK` to convert from one to the other.
For example, you might have defined a custom `RetryPolicy[cats.effect.IO]` and for another part of the app you might need a `RetryPolicy[Kleisli[monix.eval.Task]]`:
For example, you might have defined a custom `RetryPolicy[cats.effect.IO]` and for another part of the app you might need a `RetryPolicy[Kleisli[IO]]`:

```scala mdoc
import cats.effect.LiftIO
import cats.data.Kleisli
import monix.eval.Task

val customPolicy: RetryPolicy[IO] =
limitRetries[IO](5).join(constantDelay[IO](100.milliseconds))

customPolicy.mapK[Kleisli[Task, String, ?]](LiftIO.liftK[Kleisli[Task, String, ?]])
customPolicy.mapK[Kleisli[IO, String, ?]](LiftIO.liftK[Kleisli[IO, String, ?]])
```


Expand Down
12 changes: 5 additions & 7 deletions modules/docs/src/main/mdoc/docs/sleep.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,15 @@ trait Sleep[M[_]] {
```

Out of the box, the core module provides instances for any type with an implicit cats-effect
[`Timer`](https://typelevel.org/cats-effect/datatypes/timer.html) in scope.
[`Temporal`](https://typelevel.org/cats-effect/datatypes/temporal.html) in scope.

For example using `cats.effect.IO`:

```scala mdoc:silent:reset-class
import retry.Sleep
import cats.effect.{IO, Timer}
import cats.effect.IO
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.global

implicit val timer: Timer[IO] = IO.timer(global)
import cats.effect.unsafe.implicits.global

Sleep[IO].sleep(10.milliseconds)
```
Expand All @@ -37,10 +35,10 @@ Or if you're using an abstract `F[_]`:

```scala mdoc:silent:reset-class
import retry.Sleep
import cats.effect.Timer
import cats.effect.Temporal
import scala.concurrent.duration._

def sleepWell[F[_]: Timer] =
def sleepWell[F[_]: Temporal] =
Sleep[F].sleep(10.milliseconds)
```

Expand Down
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
addSbtPlugin("com.47deg" % "sbt-microsites" % "1.2.1")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.2")
addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.5")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.4.0")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.5.1")
addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.0.0")
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.10.0")
addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.8.1")