1

trueまたはを返す IO (したがって安全でない) 操作があるとしますfalse。Zio スケジューリング メカニズムを使用して、値が になるまでこれを実行したいのですがtrue、最大 N 回までです。ドキュメントからコードを採用し、それを私が達成しようとしているものに変更するには...

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) > 7
  }
}

object ScheduleUtil {
  def schedule[A] = Schedule.spaced(1.second) && Schedule.recurs(4).onDecision({
    case Decision.Done(_)                 => putStrLn(s"done trying")
    case Decision.Continue(attempt, _, _) => putStrLn(s"attempt #$attempt")
  })
}

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 => putStrLn("Exception Failed"),
    v => putStrLn(s"Succeeded with $v"))
  )
}

// run the app
ScheduleApp.main(Array())

もちろん、これは機能しません。出力はSucceeded with falseor (場合によっては)のいずれかSucceeded with trueです。定義に追加しようとしSchedule.recurUntilEqualsましたが、役に立ちませんでした。Schedule

object ScheduleUtil {
    def schedule[A] = Schedule.spaced(1.second) && Schedule.recurUntilEquals(true) && Schedule.recurs(4).onDecision({
      case Decision.Done(_)                 => putStrLn(s"done trying")
      case Decision.Continue(attempt, _, _) => putStrLn(s"attempt #$attempt")
    })
  }

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(

Zio スケジューラーを使用してそのようなユースケースを達成するにはどうすればよいですか? もちろん、makeRequestfalse を返す代わりに、意図的に例外をスローするようにタスクを再定義することもできます。これはドキュメントと同じように機能します。しかし、不必要な例外の生成/処理を避けたいと思っていました。

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) > 7) true else throw new Exception("Not true")
    }
  }
4

2 に答える 2

2

あなたの問題は、あなたが言及したようにエラーチャネルを明示的にバイパスするので、あなたが望むものの代わりにあなたが使用retryしていることです。effectrepeat

したがって、単に変更makeRequest.retry(schedule)するだけmakeRequest.repeat(schedule)で機能するはずです。

より詳細な説明については、以下の署名を検討してください。

// Schedule.spaced
def spaced(duration: Duration): Schedule[Any, Any, Long]

// Schedule.recurs
def recurs(n: Int): Schedule[Any, Any, Long]

// Schedule.recurUntilEquals
def recurUntilEquals[A](a: => A): Schedule[Any, A, A]

Scheduleには、-Env、の3 つの型パラメータがあります。は の一部である標準型と同じですが、 と は標準型や他の型とは異なります。これは、ドキュメントによると、「 type の値を消費し、 typeの値を返す定期的なスケジュール」について説明しているためです。Forおよび入力は、任意の入力値を受け入れることを示しており、拡張によって値も制約しません。これは、2 つを一緒に構成することで確認できます。-In+OutEnvRZIOInOutEAZIOScheduleInOutspacedrecursAny

val s: Schedule[Any, Any, (Long, Long)] = Schedule.spaced(1.second) && Schedule.recurs(1)

これは、の一部として使用してもコンパイラ エラーが発生しない理由でもあります。これはretry、エラー チャネルを使用しない場合、エラー チャネルに関する特定の要件がないためです。ただし、エラーretryが発生した場合にのみスケジュールを使用するため、問題が隠されますが、戻ってきたか、エラーを受信せず、スケジュールが呼び出されなかったためです。truefalse

入力制約を追加recurUntilEqualsすると、スケジュールに追加されます。

val s: Schedule[Any, Boolean, ((Long, Long), Boolean)] = Schedule.spaced(1.second) && Schedule.recurs(1) && Schedule.recurUntilEquals(true)

ここで、に入力する必要がある入力Scheduleは実際にはブール値ですがretry、署名があると言っています。

def retry[R1 <: R, S](policy: Schedule[R1, E, S])(implicit ev: CanFail[E]): ZIO[R1 with Clock, E, A]

引数の の 2 番目の位置はエラー タイプのScheduleパラメーターであり、=!=であるため、結果としてコンパイラ エラーが発生することに注意してください。policyEThrowableBoolean

それに対応して、これはの署名ですrepeat

def repeat[R1 <: R, B](schedule: Schedule[R1, A, B]): ZIO[R1 with Clock, E, B]

ここで、 がschedule実際に取るA型が、この場合は API からの応答になるか、指定Booleanされたスケジュールで期待するものと一致することがわかります。

于 2020-11-21T10:30:45.067 に答える