Я только начинаю использовать monix, отчасти для планирования повторяющейся работы в долго работающем приложении. Я буду управлять исключениями, но я бы хотел, чтобы этот моникс продолжал вызывать данную функцию, даже если я пропущу некоторые из них.
Теперь, из простого теста, после того, как запланирован повторный вызов, он не будет продолжать его вызывать после возникновения исключения:
// will print "Hi" repeatedly
scheduler.scheduleAtFixedRate(5.milliseconds, 2.milliseconds) {
println("Hi")
}
// will print "Hi" only once
scheduler.scheduleAtFixedRate(5.milliseconds, 2.milliseconds) {
println("Hi")
throw new RuntimeException("oups, forgot to catch that one")
}
Примечание: я создаю планировщик для регистрации исключений и ошибок.
Обновлено:
Я понимаю, что просто повторять эту задачу в случае неудачи - плохой замысел. Вместо этого я должен настроить правильную систему управления исключениями с отложенным перезапуском.
Я не вижу в Monix каких-либо функций для этого. Так что мне придется сделать это самому. Я оставляю вопрос на случай, если у кого-то возникнет такая же проблема, и если кто-то знает об инструментах моникса, которые могут быть полезны.
Вы всегда можете использовать scala.util.Try или простые блоки try-catch. В любом случае сбоя вы просто регистрируетесь и двигаетесь дальше. У вас даже может быть стратегия повторной попытки отказа, как показано ниже.
import scala.util._
def taskExceptionProne() = ???
var failures = 0
val maxRetries = 10
scheduler.scheduleAtFixedRate(5.milliseconds, 2.milliseconds) {
Try(taskExceptionProne) match {
Success(result) =>
//do something with the result
failures = 0
println("Task executed.")
Failure(throwable) =>
if (failures>=maxRetries) throw throwable else {
failures = failures + 1
//log failure
println(throwable.getMessage)
}
}
}
Альтернативой является использование Observable
, что упрощает сочинение. Он также имеет множество встроенных функций, поэтому вам не нужно вручную управлять своей собственной функцией.
val myTask: Task[Unit] = Task.delay(println("Execute Task")
// Note that the period will tick after you've completed the task
// So, if you have a long running task, just make sure you are aware of that
Observable
.intervalAtFixedRate(1.seconds, 1.seconds)
.mapEval(_ => myTask.onErrorRestart(maxRetries = 5))
.completedL
.startAndForget // Optional, will run in a separate fiber, so it doesn't block main thread
.runToFuture