I am using ZIO and my task is to retry request to some service with such logic (simplified):

  1. If response contains some incorrect data - make N retries, if situation have not changed - keep result
  2. If response contains not enough data - make M retries, if situation have not changed - keep result

I am planning to use .repeat function from ZIO, but can not figure out how to write schedule which will count retries individually for each condition.

package com.mycompany

import zio.Schedule.WithState
import zio.{ExitCode, Schedule, Task, URIO, ZIO, ZIOAppDefault}

import scala.util.Random

object Main3 extends ZIOAppDefault {
  def makeRequest: Task[Float] = ZIO.attempt {
    new Random().nextFloat() * 10
  }

  def makeSchedule(): WithState[(Unit, Unit), Any, Float, Float] = {
    val firstCondition =
      Schedule.recurUntil[Float](float => float > 3)
        // TODO: make only 3 tries for this condition
        .onDecision {
          case (input, value, decision) => ZIO.log(s"FirstCondition: ${input}, ${value}, ${decision}")
        }


    val secondCondition =
      Schedule.recurUntil[Float](float => float < 9)
        // TODO: make only 5 tries for this condition
        .onDecision {
          case (input, value, decision) => ZIO.log(s"SecondCondition: ${input}, ${value}, ${decision}")
        }

    firstCondition.||(secondCondition).map(_._1)
  }

  override def run: URIO[Any, ExitCode] = {
    makeRequest
      .repeat(makeSchedule())
      .tap(res => ZIO.log(f"RESULT IS: $res"))
      .exitCode
  }
}
1

There are 1 best solutions below

0
On BEST ANSWER

I found the solution:

.repetitions
.whileOutput(repetition => repetition < 3)
.passthrough[Float]

is doing the job. Calling passthrough[Float] allows to align types and get result from repeat. Final code snippet is

package com.mycompany

import zio.Schedule.WithState
import zio.{ExitCode, Schedule, Task, URIO, ZIO, ZIOAppDefault}

import scala.util.Random

object Main3 extends ZIOAppDefault {
 def makeRequest: Task[Float] = ZIO.attempt {
   new Random().nextFloat() * 10
 }

 def makeSchedule() = {
   val firstCondition =
     Schedule.recurUntil[Float](float => float > 8)
       .repetitions
       .whileOutput(repetition => repetition < 3)
       .passthrough[Float]
       .onDecision {
         case (input, value, decision) => ZIO.log(s"FirstCondition: ${input}, ${value}, ${decision}")
       }


   val secondCondition: WithState[(Unit, Long), Any, Float, Float] =
     Schedule.recurUntil[Float](float => float < 9)
       .repetitions
       .whileOutput(repetition => repetition < 5)
       .passthrough[Float]
       .onDecision {
         case (input, value, decision) => ZIO.log(s"SecondCondition: ${input}, ${value}, ${decision}")
       }

   firstCondition.||(secondCondition).map(_._1)
 }

 override def run: URIO[Any, ExitCode] = {
   makeRequest
     .repeat(makeSchedule())
     .tap(res => ZIO.log(f"RESULT IS: $res"))
     .exitCode
 }
}