title: How can I recur a Zio schedule until a particular value is produced?
body: <p>Suppose I have an IO (therefore unsafe) operation that will either return <code>true</code> or <code>false</code>.  I want to use the Zio scheduling mechanism to execute this until the value is <code>true</code>, but only up to a maximum of N times.  To adopt the code from <a href="https://zio.dev/docs/usecases/usecases_scheduling" rel="nofollow noreferrer">the documentation</a> and change it to what I'm trying to achieve...</p>
  <pre><code>import zio._
  import zio.duration._
  import zio.console._
  import zio.clock._
  import java.util.Random
  
  object API {
    // our API method will return true about 30% of the time, but
    // return false the rest of the time (instead of throwing an
    // exception, as is shown in documentation)
    def makeRequest: Task[Boolean] = Task.effect {
      new Random().nextInt(10) &gt; 7
    }
  }
  
  object ScheduleUtil {
    def schedule[A] = Schedule.spaced(1.second) &amp;&amp; Schedule.recurs(4).onDecision({
      case Decision.Done(_)                 =&gt; putStrLn(s&quot;done trying&quot;)
      case Decision.Continue(attempt, _, _) =&gt; putStrLn(s&quot;attempt #$attempt&quot;)
    })
  }
  
  import ScheduleUtil._
  import API._
  
  object ScheduleApp extends scala.App {
  
    implicit val rt: Runtime[Clock with Console] = Runtime.default
  
    rt.unsafeRun(makeRequest.retry(schedule).foldM(
      ex =&gt; putStrLn(&quot;Exception Failed&quot;),
      v =&gt; putStrLn(s&quot;Succeeded with $v&quot;))
    )
  }
  
  // run the app
  ScheduleApp.main(Array())
  </code></pre>
  <p>This doesn't work, of course.  The output is either <code>Succeeded with false</code> or (occasionally) <code>Succeeded with true</code>.  I tried adding <code>Schedule.recurUntilEquals</code> to the <code>Schedule</code> definition, but to no avail.</p>
  <pre><code>object ScheduleUtil {
      def schedule[A] = Schedule.spaced(1.second) &amp;&amp; Schedule.recurUntilEquals(true) &amp;&amp; Schedule.recurs(4).onDecision({
        case Decision.Done(_)                 =&gt; putStrLn(s&quot;done trying&quot;)
        case Decision.Continue(attempt, _, _) =&gt; putStrLn(s&quot;attempt #$attempt&quot;)
      })
    }
  
  import ScheduleUtil._
  
  // re-define ScheduleApp in the exact same way as above, and the following error results:
  
  cmd93.sc:5: polymorphic expression cannot be instantiated to expected type;
   found   : [A]zio.Schedule[zio.console.Console,Boolean,((Long, Boolean), Long)]
      (which expands to)  [A]zio.Schedule[zio.Has[zio.console.Console.Service],Boolean,((Long, Boolean), Long)]
   required: zio.Schedule[?,Throwable,?]
    rt.unsafeRun(makeRequest.retry(schedule).foldM(
  </code></pre>
  <p>How can I accomplish such a use case using the Zio scheduler?  Of course, I can redefine the <code>makeRequest</code> task to deliberately throw an exception, instead of returning false, and this works just as in the documentation.  But I was hoping to avoid unnecessary exception generation/handling.</p>
  <pre><code>object API {
      // our API method will return true about 30% of the time, but
      // return false the rest of the time (instead of throwing an
      // exception, as is shown in documentation)
      def makeRequest = Task.effect {
        if (new Random().nextInt(10) &gt; 7) true else throw new Exception(&quot;Not true&quot;)
      }
    }
  </code></pre>