Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
1
Error Management
ZIO vs Future
Dublin Scala Meetup, May 11th
John A. De Goes   @jdegoes
Kai @kaidaxofficial
...with help ...
Agenda
A Tale of Two Effects
2
Next-Gen Debugging Conclusion
Managing Errors
3
A TALE OF
TWO EFFECTS
FUTURE
Parallel
Future enables parallel
computations and
non-blocking gathering.
Error
Future has a built-in error
channel for
Th...
5
Future ZIO Effect
go running
Procedural Functional
def program: Unit = {
println("What’s your name?")
val name = readLine()
println(s"Howdy. $name!")
r...
7
Future ZIO
Performance > 100x slower > 100x faster
Cancellation & Timeouts 𐄂 ✔
Effect Combinators 𐄂 ✔
Resource Safety 𐄂 ...
8
ZIO[R, E, A]
Environment Type
Failure Type
Success Type
9
ZIO[R, E, A]
~
R => Either[E, A]
10
type Task [ +A] = ZIO[Any, Throwable, A]
type UIO [ +A] = ZIO[Any, Nothing, A]
type TaskR[+R,+A] = ZIO[ R, Throwable, A...
11
type Task [ +A] = ZIO[Any, Throwable, A]
type UIO [ +A] = ZIO[Any, Nothing, A]
type TaskR[+R,+A] = ZIO[ R, Throwable, A...
12
type Task [ +A] = ZIO[Any, Throwable, A]
type UIO [ +A] = ZIO[Any, Nothing, A]
type TaskR[+R,+A] = ZIO[ R, Throwable, A...
13
type Task [ +A] = ZIO[Any, Throwable, A]
type UIO [ +A] = ZIO[Any, Nothing, A]
type TaskR[+R,+A] = ZIO[ R, Throwable, A...
ZIO[R, E, A]
Synchronous Asynchronous Errors Resource
ZIO.succeed(…)
ZIO.effect(…)
ZIO.effectTotal(…)
effectBlocking(…)
ZI...
15
ERROR
MANAGEMENT
FUTURE
Fail Domain errors, business errors,
transient errors, expected errors...
Expected Errors
Not Reflected in Types
DieSystem ...
17
ERROR DUALITY
Not Reflected in TypesNot Reflected in Types
val failed: Future[Nothing] =
Future.failed(new Exception)
val...
18
ERROR DUALITY
Not Reflected in TypesReflected in Types
val failed: IO[String, Nothing] =
ZIO.fail(“Uh oh!”)
val died: IO[...
19
ERROR COMPOSITION
e1
e2t
First Error
20
ERROR COMPOSITION
e1
e2t
Second Error
21
ERROR COMPOSITION
e1
e2tFinalizer Error
22
ERROR COMPOSITION
e1
e2t
?
23
ERROR COMPOSITION
e1
e2t
FUTURE
Thrown away!!!Reported on side channel!!!
24
ERROR COMPOSITION
e1
e2t
Cause[E]
25
ERROR COMPOSITION
e1
e2t
Cause[E]
Cause.Fail(e1)
26
ERROR COMPOSITION
e1
e2t
Cause[E]
Cause.Both(
Cause.Fail(e1),
Cause.Fail(e2))
27
ERROR COMPOSITION
e1
e2t
Cause[E]
Cause.Both(
Cause.Fail(e1),
Cause.Then(
Cause.Fail(e2),
Cause.Die(t))
zio.FiberFailure: Fiber failed.
╥
╠══╗
║ ║
║ ║
║ ║
║ ╠─ A checked error was not handled:
║ ║
Failed(DatabaseUnreachableErr...
Asynchronous
29
ERROR PROPAGATION
Synchronous
ConcurrentParallel
Resource
Asynchronous
30
ERROR PROPAGATION
Synchronous
ConcurrentParallel
Resource
FUTURE
Asynchronous
31
ERROR PROPAGATION
Synchronous
ConcurrentParallel
Resource
32
ERROR RECOVERY
Fallback Catching Folding Value
ZIO#orElse(…)
ZIO#orElseEither(…)
ZIO#catchAll(…)
ZIO#catchSome(…)
ZIO#f...
33
ERROR RECOVERY
Fallback Catching Folding Value
ZIO#orElse(…)
ZIO#orElseEither(…)
ZIO#catchAll(…)
ZIO#catchSome(…)
ZIO#f...
34
ERROR RECOVERY
Fallback Catching Folding Value
ZIO#orElse(…)
ZIO#orElseEither(…)
ZIO#catchAll(…)
ZIO#catchSome(…)
ZIO#f...
35
ERROR RECOVERY
Fallback Catching Folding Value
ZIO#orElse(…)
ZIO#orElseEither(…)
ZIO#catchAll(…)
ZIO#catchSome(…)
ZIO#f...
36
ERROR RECOVERY
Fallback Catching Folding Value
ZIO#orElse(…)
ZIO#orElseEither(…)
ZIO#catchAll(…)
ZIO#catchSome(…)
ZIO#f...
37
ERROR RECOVERY
Fallback Catching Folding Value
ZIO#orElse(…)
ZIO#orElseEither(…)
ZIO#catchAll(…)
ZIO#catchSome(…)
ZIO#f...
38
ERROR RECOVERY
Fallback Catching Folding Value
ZIO#orElse(…)
ZIO#orElseEither(…)
ZIO#catchAll(…)
ZIO#catchSome(…)
ZIO#f...
39
BEST
PRACTICES
40
1. DON’T TYPE UNEXPECTED ERRORS
ZIO.effect(httpClient.get(url)).refineOrDie {
case e : TemporarilyUnavailable => e
}.re...
41
2. DO EXTEND EXCEPTION WITH SEALED TRAITS
sealed trait UserServiceError
extends Exception
case class InvalidUserId(id: ...
42
2. DO EXTEND EXCEPTION WITH SEALED TRAITS
userServiceError match {
case InvalidUserId(id) => ...
case ExpiredAuth(id) =...
43
2. DO EXTEND EXCEPTION WITH SEALED TRAITS
for {
service <- userAuth(token)
_ <- service.userProfile(userId)
body <- gen...
44
2. DO EXTEND EXCEPTION WITH SEALED TRAITS
for {
service <- userAuth(token)
_ <- service.userProfile(userId)
body <- gen...
45
2. DO EXTEND EXCEPTION WITH SEALED TRAITS
for {
service <- userAuth(token)
_ <- service.userProfile(userId)
body <- gen...
46
2. DO EXTEND EXCEPTION WITH SEALED TRAITS
for {
service <- userAuth(token)
_ <- service.userProfile(userId)
body <- gen...
47
2. DO EXTEND EXCEPTION WITH SEALED TRAITS
for {
service <- userAuth(token)
_ <- service.userProfile(userId)
body <- gen...
48
3. DON’T REFLEXIVELY LOG ERRORS
uploadFile(“contacts.csv”).catchAll { error =>
// Log error and re-fail:
for {
_ <- log...
49
4. DO GET TO KNOW UIO
type UIO[+A] = ZIO[Any, Nothing, A]
Cannot fail!
lazy val processed: UIO[Unit] =
processUpload(upload).either.flatMap {
case Left (_) => processed.delay(1.minute)
case Rig...
lazy val processed: UIO[Unit] =
processUpload(upload).either.flatMap {
case Left (_) => processed.delay(1.minute)
case Rig...
52
4. DO GET TO KNOW UIO
lazy val processed: UIO[Unit] =
processUpload(upload).either.flatMap {
case Left (_) => processed...
NEXT-GENERATION
DEBUGGING
54
def asyncDbCall(sql: SQL): Future[Result]
def selectHumans(): Future[Result] = ...asyncDbCall(...)...
def selectPets():...
55
def asyncDbCall(sql: SQL): Future[Result]
def selectHumans(): Future[Result] = ...asyncDbCall(...)...
def selectPets():...
56
Which function failed, selectHumans or selectPets?
FUTURE
def asyncDbCall(sql: SQL): Future[Result]
def selectHumans():...
57
Which function failed, selectHumans or selectPets?
FUTURE
Only the last operation is mentioned
There is NO way to know!...
58
Asynchronous
def myQuery =
for {
_ <- UIO(println(“Querying!”))
res <- queryDatabase
} yield res
59
Failure!
def myQuery =
for {
_ <- UIO(println(“Querying!”))
res <- queryDatabase
} yield res
60
def myQuery =
for {
_ <- UIO(println(“Querying!”))
res <- queryDatabase
} yield res
Fiber:0 ZIO Execution trace:
at myQ...
61
def myQuery =
UIO(println(“Querying!”))
.flatMap(_ =>
queryDatabase
.map(res => res))
Fiber:0 ZIO Execution trace:
at m...
62
def myQuery =
UIO(println(“Querying!”))
.flatMap(_ =>
queryDatabase
.map(res => res))
Fiber:0 ZIO Execution trace:
at m...
63
def myQuery =
UIO(println(“Querying!”))
.flatMap(_ =>
queryDatabase
.map(res => res))
Fiber:0 ZIO Execution trace:
at m...
64
def asyncDbCall(sql: SQL): Task[Result]
val selectHumans: Task[Result] = ...asyncDbCall(...)...
val selectPets: Task[Re...
65
def asyncDbCall(sql: SQL): Task[Result]
val selectHumans: Task[Result] = ...asyncDbCall(...)...
val selectPets: Task[Re...
66
def asyncDbCall(sql: SQL): Task[Result]
val selectHumans: Task[Result] = ...asyncDbCall(...)...
val selectPets: Task[Re...
67
EXECUTION TRACES
def doWork(condition: Boolean) = {
if (condition) {
doSideWork()
}
doMainWork()
}
java.lang.Exception:...
68
EXECUTION TRACES
def doWork(condition: Boolean) =
for {
_ <- IO.when(condition)(doSideWork)
_ <- doMainWork
} yield ()
...
69
CONCURRENT TRACES
uploadUsers uploadPets
uploadTo(target)
error!
def uploadUsers(users: List[User]): Task[Unit] =
IO.fo...
70
CONCURRENT TRACES
uploadUsers uploadPets
uploadTo(target)
error!
java.lang.Exception: Expired credentials
at example$.$...
71
TAGLESS FINAL TRACES
Gain insights into FP libraries
72
● Tracing is fast , impact is negligible for real apps
● > 50x faster than Future
● ...even on synthetic benchmarks!
● ...
I
73
CONCLUSION
https://github.com/zio
https://gitter.im/zio/core
https://zio.dev
@jdegoes
@kaidaxofficial
@shirshovp
Upcoming SlideShare
Loading in …5
×

Error Management: Future vs ZIO

7,498 views

Published on

Modern applications are concurrent, parallel, asynchronous, and synchronous; they utilize many different subsystems, including network systems, actor systems, distributed systems, and more. Across all these modes of computation and different subsystems, the one constant is failure. Errors happen everywhere, and taming their monstrous complexity in a way that helps developers write correct code and troubleshoot failures is one of the hardest challenges of modern application development.

In this presentation, created just for the Dublin Scala Meetup, John A. De Goes and Kai ⁣from 7mind.io will take attendees on a tour of error management in Scala, comparing and contrasting Scala's own Future type, and the ZIO effect type. You'll see how functional effects provide features that go way beyond Future: including unified errors across all modes of computation, powerful error operators, lossless error propagation, compiler-assisted error handling, and a stunning new feature for debugging, sponsored by Irish consultancy 7mind.io, will be unveiled exclusively at this presentation.

Come learn about how modern functional effect systems like ZIO provide compelling new solutions to the problems of everyday error management.

Published in: Technology

Error Management: Future vs ZIO

  1. 1. 1 Error Management ZIO vs Future Dublin Scala Meetup, May 11th John A. De Goes   @jdegoes Kai @kaidaxofficial ...with help of Pavel Shirshov @shirshovp
  2. 2. Agenda A Tale of Two Effects 2 Next-Gen Debugging Conclusion Managing Errors
  3. 3. 3 A TALE OF TWO EFFECTS FUTURE
  4. 4. Parallel Future enables parallel computations and non-blocking gathering. Error Future has a built-in error channel for Throwable-based errors. Eager Future is not referentially transparent; refactoring may change behavior. 4 FUTURE Async Future enables non-blocking code that efficiently uses threads.
  5. 5. 5 Future ZIO Effect go running
  6. 6. Procedural Functional def program: Unit = { println("What’s your name?") val name = readLine() println(s"Howdy. $name!") return () } val program = for { _ <- putStrLn("What’s your name?") name <- getStrLn _ <- putStrLn(s"Howdy, $name") } yield ()
  7. 7. 7 Future ZIO Performance > 100x slower > 100x faster Cancellation & Timeouts 𐄂 ✔ Effect Combinators 𐄂 ✔ Resource Safety 𐄂 ✔ Fiber Concurrency 𐄂 ✔ Equational & Type Reasoning 𐄂 ✔ Testability 𐄂 ✔ Error Management & Debugging ? ?
  8. 8. 8 ZIO[R, E, A] Environment Type Failure Type Success Type
  9. 9. 9 ZIO[R, E, A] ~ R => Either[E, A]
  10. 10. 10 type Task [ +A] = ZIO[Any, Throwable, A] type UIO [ +A] = ZIO[Any, Nothing, A] type TaskR[+R,+A] = ZIO[ R, Throwable, A] type IO [+E,+A] = ZIO[Any, E, A]
  11. 11. 11 type Task [ +A] = ZIO[Any, Throwable, A] type UIO [ +A] = ZIO[Any, Nothing, A] type TaskR[+R,+A] = ZIO[ R, Throwable, A] type IO [+E,+A] = ZIO[Any, E, A]
  12. 12. 12 type Task [ +A] = ZIO[Any, Throwable, A] type UIO [ +A] = ZIO[Any, Nothing, A] type TaskR[+R,+A] = ZIO[ R, Throwable, A] type IO [+E,+A] = ZIO[Any, E, A]
  13. 13. 13 type Task [ +A] = ZIO[Any, Throwable, A] type UIO [ +A] = ZIO[Any, Nothing, A] type TaskR[+R,+A] = ZIO[ R, Throwable, A] type IO [+E,+A] = ZIO[Any, E, A]
  14. 14. ZIO[R, E, A] Synchronous Asynchronous Errors Resource ZIO.succeed(…) ZIO.effect(…) ZIO.effectTotal(…) effectBlocking(…) ZIO.effectAsync(…) ZIO.effectAsyncMaybe(…) ZIO.effectAsyncInte…(…) ZIO.fromFuture(…) ZIO.fail(…) ZIO.fromOption(…) ZIO.fromEither(…) ZIO.fromTry(…) ZIO.bracket(…) ZIO.reserve(…) ZIO.ensuring(…) fromAutoCloseable(…)
  15. 15. 15 ERROR MANAGEMENT FUTURE
  16. 16. Fail Domain errors, business errors, transient errors, expected errors... Expected Errors Not Reflected in Types DieSystem errors, fatal errors, unanticipated errors, defects... Unexpected Errors Reflected in Types 16 ERROR DUALITY
  17. 17. 17 ERROR DUALITY Not Reflected in TypesNot Reflected in Types val failed: Future[Nothing] = Future.failed(new Exception) val died: Future[Nothing] = Future(throw new Error) FUTURE
  18. 18. 18 ERROR DUALITY Not Reflected in TypesReflected in Types val failed: IO[String, Nothing] = ZIO.fail(“Uh oh!”) val died: IO[Nothing, Nothing] = ZIO.dieMessage(“Uh oh!”)
  19. 19. 19 ERROR COMPOSITION e1 e2t First Error
  20. 20. 20 ERROR COMPOSITION e1 e2t Second Error
  21. 21. 21 ERROR COMPOSITION e1 e2tFinalizer Error
  22. 22. 22 ERROR COMPOSITION e1 e2t ?
  23. 23. 23 ERROR COMPOSITION e1 e2t FUTURE Thrown away!!!Reported on side channel!!!
  24. 24. 24 ERROR COMPOSITION e1 e2t Cause[E]
  25. 25. 25 ERROR COMPOSITION e1 e2t Cause[E] Cause.Fail(e1)
  26. 26. 26 ERROR COMPOSITION e1 e2t Cause[E] Cause.Both( Cause.Fail(e1), Cause.Fail(e2))
  27. 27. 27 ERROR COMPOSITION e1 e2t Cause[E] Cause.Both( Cause.Fail(e1), Cause.Then( Cause.Fail(e2), Cause.Die(t))
  28. 28. zio.FiberFailure: Fiber failed. ╥ ╠══╗ ║ ║ ║ ║ ║ ║ ║ ╠─ A checked error was not handled: ║ ║ Failed(DatabaseUnreachableError) ║ ║ ║ ╠─ A finalizer threw an error: ║ ▼ Die(IndexOutOfBoundsException()) ║ ╠─ A checked error was not handled: ▼ Failed(UserIdNotFoundError) 28 ERROR COMPOSITION e2 t e1
  29. 29. Asynchronous 29 ERROR PROPAGATION Synchronous ConcurrentParallel Resource
  30. 30. Asynchronous 30 ERROR PROPAGATION Synchronous ConcurrentParallel Resource FUTURE
  31. 31. Asynchronous 31 ERROR PROPAGATION Synchronous ConcurrentParallel Resource
  32. 32. 32 ERROR RECOVERY Fallback Catching Folding Value ZIO#orElse(…) ZIO#orElseEither(…) ZIO#catchAll(…) ZIO#catchSome(…) ZIO#fold(…, …) ZIO#foldM(…, …) effect1.orElse(effect2) future1.fallback(future2) ZIO#either ZIO#run FUTURE
  33. 33. 33 ERROR RECOVERY Fallback Catching Folding Value ZIO#orElse(…) ZIO#orElseEither(…) ZIO#catchAll(…) ZIO#catchSome(…) ZIO#fold(…, …) ZIO#foldM(…, …) effect.catchAll(f) future.recoverWith(pf) ZIO#either ZIO#run FUTURE
  34. 34. 34 ERROR RECOVERY Fallback Catching Folding Value ZIO#orElse(…) ZIO#orElseEither(…) ZIO#catchAll(…) ZIO#catchSome(…) ZIO#fold(…, …) ZIO#foldM(…, …) effect.catchSome(pf) future.recoverWith(pf) ZIO#either ZIO#run FUTURE
  35. 35. 35 ERROR RECOVERY Fallback Catching Folding Value ZIO#orElse(…) ZIO#orElseEither(…) ZIO#catchAll(…) ZIO#catchSome(…) ZIO#fold(…, …) ZIO#foldM(…, …) effect.fold(err, succ) ZIO#either ZIO#run FUTURE
  36. 36. 36 ERROR RECOVERY Fallback Catching Folding Value ZIO#orElse(…) ZIO#orElseEither(…) ZIO#catchAll(…) ZIO#catchSome(…) ZIO#fold(…, …) ZIO#foldM(…, …) effect.foldM(err, succ) ZIO#either ZIO#run FUTURE
  37. 37. 37 ERROR RECOVERY Fallback Catching Folding Value ZIO#orElse(…) ZIO#orElseEither(…) ZIO#catchAll(…) ZIO#catchSome(…) ZIO#fold(…, …) ZIO#foldM(…, …) effect.either ZIO#either ZIO#run FUTURE
  38. 38. 38 ERROR RECOVERY Fallback Catching Folding Value ZIO#orElse(…) ZIO#orElseEither(…) ZIO#catchAll(…) ZIO#catchSome(…) ZIO#fold(…, …) ZIO#foldM(…, …) ZIO#either ZIO#run effect.run FUTURE
  39. 39. 39 BEST PRACTICES
  40. 40. 40 1. DON’T TYPE UNEXPECTED ERRORS ZIO.effect(httpClient.get(url)).refineOrDie { case e : TemporarilyUnavailable => e }.retry(RetryPolicy).orDie : IO[TemporarilyUnavailable, Response]
  41. 41. 41 2. DO EXTEND EXCEPTION WITH SEALED TRAITS sealed trait UserServiceError extends Exception case class InvalidUserId(id: ID) extends UserServiceError case class ExpiredAuth(id: ID) extends UserServiceError UserServiceError InvalidUserId ExpiredAuth
  42. 42. 42 2. DO EXTEND EXCEPTION WITH SEALED TRAITS userServiceError match { case InvalidUserId(id) => ... case ExpiredAuth(id) => ... }
  43. 43. 43 2. DO EXTEND EXCEPTION WITH SEALED TRAITS for { service <- userAuth(token) _ <- service.userProfile(userId) body <- generateEmail(orderDetails) receipt <- sendEmail(“Your Order Details”, body, profile.email) } yield receipt ExpiredAuth
  44. 44. 44 2. DO EXTEND EXCEPTION WITH SEALED TRAITS for { service <- userAuth(token) _ <- service.userProfile(userId) body <- generateEmail(orderDetails) receipt <- sendEmail(“Your Order Details”, body, profile.email) } yield receipt InvalidUserId
  45. 45. 45 2. DO EXTEND EXCEPTION WITH SEALED TRAITS for { service <- userAuth(token) _ <- service.userProfile(userId) body <- generateEmail(orderDetails) receipt <- sendEmail(“Your Order Details”, body, profile.email) } yield receipt Nothing
  46. 46. 46 2. DO EXTEND EXCEPTION WITH SEALED TRAITS for { service <- userAuth(token) _ <- service.userProfile(userId) body <- generateEmail(orderDetails) receipt <- sendEmail(“Your Order Details”, body, profile.email) } yield receipt EmailDeliveryError
  47. 47. 47 2. DO EXTEND EXCEPTION WITH SEALED TRAITS for { service <- userAuth(token) _ <- service.userProfile(userId) body <- generateEmail(orderDetails) receipt <- sendEmail(“Your Order Details”, body, profile.email) } yield receipt IO[Exception, Receipt]
  48. 48. 48 3. DON’T REFLEXIVELY LOG ERRORS uploadFile(“contacts.csv”).catchAll { error => // Log error and re-fail: for { _ <- logger.error(error) _ <- ZIO.fail(error) } yield () }
  49. 49. 49 4. DO GET TO KNOW UIO type UIO[+A] = ZIO[Any, Nothing, A] Cannot fail!
  50. 50. lazy val processed: UIO[Unit] = processUpload(upload).either.flatMap { case Left (_) => processed.delay(1.minute) case Right(_) => ZIO.succeed(()) } 50 4. DO GET TO KNOW UIO Fails with UploadError
  51. 51. lazy val processed: UIO[Unit] = processUpload(upload).either.flatMap { case Left (_) => processed.delay(1.minute) case Right(_) => ZIO.succeed(()) } 51 4. DO GET TO KNOW UIO Fails with Nothing
  52. 52. 52 4. DO GET TO KNOW UIO lazy val processed: UIO[Unit] = processUpload(upload).either.flatMap { case Left (_) => processed.delay(1.minute) case Right(_) => ZIO.succeed(()) } Fails with Nothing
  53. 53. NEXT-GENERATION DEBUGGING
  54. 54. 54 def asyncDbCall(sql: SQL): Future[Result] def selectHumans(): Future[Result] = ...asyncDbCall(...)... def selectPets(): Future[Result] = ...asyncDbCall(...)... FUTURE
  55. 55. 55 def asyncDbCall(sql: SQL): Future[Result] def selectHumans(): Future[Result] = ...asyncDbCall(...)... def selectPets(): Future[Result] = ...asyncDbCall(...)... FUTURE Which function failed, selectHumans or selectPets? PostgresException: Syntax error at or near 42 at example$.getConnection(example.scala:43) at example$.$anonfun$asyncDbCall$1(example.scala:23) at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:658) at scala.util.Success.$anonfun$map$1(Try.scala:255) at scala.util.Success.map(Try.scala:213) at scala.concurrent.Future.$anonfun$map$1(Future.scala:292) at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:33) at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:33) at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:64) 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)
  56. 56. 56 Which function failed, selectHumans or selectPets? FUTURE def asyncDbCall(sql: SQL): Future[Result] def selectHumans(): Future[Result] = ...asyncDbCall(...)... def selectPets(): Future[Result] = ...asyncDbCall(...)... Only the last operation is mentioned PostgresException: Syntax error at or near 42 at example$.getConnection(example.scala:43) at example$.$anonfun$asyncDbCall$1(example.scala:23) at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:658) at scala.util.Success.$anonfun$map$1(Try.scala:255) at scala.util.Success.map(Try.scala:213) at scala.concurrent.Future.$anonfun$map$1(Future.scala:292) at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:33) at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:33) at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:64) 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)
  57. 57. 57 Which function failed, selectHumans or selectPets? FUTURE Only the last operation is mentioned There is NO way to know!!! def asyncDbCall(sql: SQL): Future[Result] def selectHumans(): Future[Result] = ...asyncDbCall(...)... def selectPets(): Future[Result] = ...asyncDbCall(...)... PostgresException: Syntax error at or near 42 at example$.getConnection(example.scala:43) at example$.$anonfun$asyncDbCall$1(example.scala:23) at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:658) at scala.util.Success.$anonfun$map$1(Try.scala:255) at scala.util.Success.map(Try.scala:213) at scala.concurrent.Future.$anonfun$map$1(Future.scala:292) at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:33) at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:33) at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:64) 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)
  58. 58. 58 Asynchronous def myQuery = for { _ <- UIO(println(“Querying!”)) res <- queryDatabase } yield res
  59. 59. 59 Failure! def myQuery = for { _ <- UIO(println(“Querying!”)) res <- queryDatabase } yield res
  60. 60. 60 def myQuery = for { _ <- UIO(println(“Querying!”)) res <- queryDatabase } yield res Fiber:0 ZIO Execution trace: at myQuery(example.scala:4) at myQuery(example.scala:3) Fiber:0 was supposed to continue to: a future continuation at myQuery(example.scala:5) Failure!
  61. 61. 61 def myQuery = UIO(println(“Querying!”)) .flatMap(_ => queryDatabase .map(res => res)) Fiber:0 ZIO Execution trace: at myQuery(example.scala:4) at myQuery(example.scala:3) Fiber:0 was supposed to continue to: a future continuation at myQuery(example.scala:5)
  62. 62. 62 def myQuery = UIO(println(“Querying!”)) .flatMap(_ => queryDatabase .map(res => res)) Fiber:0 ZIO Execution trace: at myQuery(example.scala:4) at myQuery(example.scala:3) Fiber:0 was supposed to continue to: a future continuation at myQuery(example.scala:5) The Past
  63. 63. 63 def myQuery = UIO(println(“Querying!”)) .flatMap(_ => queryDatabase .map(res => res)) Fiber:0 ZIO Execution trace: at myQuery(example.scala:4) at myQuery(example.scala:3) Fiber:0 was supposed to continue to: a future continuation at myQuery(example.scala:5) The Past The Future
  64. 64. 64 def asyncDbCall(sql: SQL): Task[Result] val selectHumans: Task[Result] = ...asyncDbCall(...)... val selectPets: Task[Result] = ...asyncDbCall(...)...
  65. 65. 65 def asyncDbCall(sql: SQL): Task[Result] val selectHumans: Task[Result] = ...asyncDbCall(...)... val selectPets: Task[Result] = ...asyncDbCall(...)... Fiber:0 ZIO Execution trace: at asyncDbCall(example.scala:22) at selectHumans(example.scala:26) Fiber:0 was supposed to continue to: a future continuation at selectHumans(example.scala:27)
  66. 66. 66 def asyncDbCall(sql: SQL): Task[Result] val selectHumans: Task[Result] = ...asyncDbCall(...)... val selectPets: Task[Result] = ...asyncDbCall(...)... Fiber:0 ZIO Execution trace: at asyncDbCall(example.scala:22) at selectHumans(example.scala:26) Fiber:0 was supposed to continue to: a future continuation at selectHumans(example.scala:27) Gotcha!
  67. 67. 67 EXECUTION TRACES def doWork(condition: Boolean) = { if (condition) { doSideWork() } doMainWork() } java.lang.Exception: Worker failed! at example$.doMainWork(example.scala:54) at example$.doWork(example.scala:50) at example$$anon$1.run(example.scala:60) No mention of doSideWork() PROCEDURAL
  68. 68. 68 EXECUTION TRACES def doWork(condition: Boolean) = for { _ <- IO.when(condition)(doSideWork) _ <- doMainWork } yield () Fiber:0 ZIO Execution trace: at example$.doMainWork(example.scala:27) at example$.doWork(example.scala:23) at example$.doSideWork(example.scala:26) The conditional was true!
  69. 69. 69 CONCURRENT TRACES uploadUsers uploadPets uploadTo(target) error! def uploadUsers(users: List[User]): Task[Unit] = IO.foreachPar_(users.map(toJSON))(uploadTo(dest1)) def uploadPets(pets: List[Pet]): Task[Unit] = IO.foreachPar_(pets.map(toJSON))(uploadTo(dest2)) def uploadTo(dest: URL)(json: JSON): Task[Unit] = ...
  70. 70. 70 CONCURRENT TRACES uploadUsers uploadPets uploadTo(target) error! java.lang.Exception: Expired credentials at example$.$anonfun$uploadTo$1(example.scala:28) Fiber:1 ZIO Execution trace: at example$.uploadTo(example.scala:28) Fiber:1 was supposed to continue to: <empty trace> Fiber:1 was spawned by: ╥ ╠─ Fiber:0 ZIO Execution trace: <empty trace> ║ ║ Fiber:0 was supposed to continue to: ║ example$.uploadUsers(example.scala:21)
  71. 71. 71 TAGLESS FINAL TRACES Gain insights into FP libraries
  72. 72. 72 ● Tracing is fast , impact is negligible for real apps ● > 50x faster than Future ● ...even on synthetic benchmarks! ● Impact can be limited by config ● Much lower than monad transformers [10x] ● Enabled by default, no Java agents, no ceremony Disable if tracing is a hot spot effect.untraced MADE FOR PRODUCTION
  73. 73. I 73 CONCLUSION https://github.com/zio https://gitter.im/zio/core https://zio.dev @jdegoes @kaidaxofficial @shirshovp

×