and a fallback: def runRequests(userId: String): Future[Option[User]] = { val mainRequest: Future[Option[User]] = getUser(mainDb, userId) val fallbackRequest: Future[Option[User]] = getUser(fallbackDb, userId) mainRequest.recoverWith { case e => log.warn("Main DB failed. Falling back to secondary") fallbackRequest } } Itamar Ravid - @itrvd 11
Future that doesn't necessarily fail with Throwable • A purely functional description for asynchronous, concurrent programs • Something that is kind-of like Config => Either[AppError, String] Itamar Ravid - @itrvd 14
widens the error: val composed: ZIO[Any, AppError, User] = for { token <- authenticate user <- getUser(token) } yield user No annotations, no compiler helping, nothing! Itamar Ravid - @itrvd 24
effect monads) do not faithfully represent: def getUser(id: Int): ZIO[Any, Throwable, User] val twoUsers: ZIO[Any, Throwable, (User, User)] = getUser(10) zipPar getUser(20) We know what happens if one of them fails. What happens when both fail? Itamar Ravid - @itrvd 25
can fork computations using fork: val heavyComputation: ZIO[Any, Throwable, Int] for { fiber: Fiber[Throwable, Int] <- heavyComputation.fork // do other stuff result <- fiber.join } yield result Itamar Ravid - @itrvd 34
= ZSchedule.exponential(50.millis) && ZSchedule.recurs(5) This schedule will repeat using the max delay, for as long as both schedules repeat. Itamar Ravid - @itrvd 55
trigger across threads: for { promise <- Promise.make[Throwable, String] // Wait on the promise in a background fiber: fiber <- (for { result <- promise.await _ <- UIO(println(s"Received $result")) } yield ()).fork // Resolve it from this fiber: _ <- promise.succeed("42") // Wait for the fiber to exit: _ <- fiber.join } yield () Itamar Ravid - @itrvd 59
trigger across threads: for { promise <- Promise.make[Throwable, String] // Wait on the promise in a background fiber: fiber <- (for { result <- promise.await _ <- UIO(println(s"Received $result")) } yield ()).fork // Make it fail: _ <- promise.fail(new Exception) // Wait for the fiber to exit: _ <- fiber.join } yield () Itamar Ravid - @itrvd 60
crawler: def httpCall(url: String): Future[String] def first = httpCall("first:8080") def second = httpCall("second:8080") val result: Future[(String, String)] = first zip second Itamar Ravid - @itrvd 66
a failure. This is your stack trace: java.lang.RuntimeException at test.Crawler$.$anonfun$httpCall$1(bla.scala:8) at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:660) at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:430) at scala.concurrent.BatchingExecutor$AbstractBatch.runN(BatchingExecutor.scala:134) at scala.concurrent.BatchingExecutor$AsyncBatch.apply(BatchingExecutor.scala:163) at scala.concurrent.BatchingExecutor$AsyncBatch.apply(BatchingExecutor.scala:146) at scala.concurrent.BlockContext$.usingBlockContext(BlockContext.scala:107) at scala.concurrent.BatchingExecutor$AsyncBatch.run(BatchingExecutor.scala:154) at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402) at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289) at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056) at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692) at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157) Which call failed??? Itamar Ravid - @itrvd 67
A checked error was not handled. java.lang.RuntimeException // <regular stack trace> Fiber:0 was supposed to continue to: a future continuation at zio.ZIO.zipWith(ZIO.scala:788) Fiber:0 execution trace: at ammonite.$file.bla$.httpCall(bla.scala:6) at ammonite.$file.bla$.google(bla.scala:8) Itamar Ravid - @itrvd 68
to Israel to teach a workshop about ZIO, graciously hosted by IronSource! https://www.eventbrite.com/e/advanced-async-and-concurrent- programming-with-zio-by-john-a-de-goes-tickets-63867611746 Itamar Ravid - @itrvd 84