Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server
Unsucking Error Handling with Futures
-
Upload
gary-coady -
Category
Technology
-
view
243 -
download
1
Transcript of Unsucking Error Handling with Futures
![Page 2: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/2.jpg)
Option[A]Error Handling: Possible Absence of a Value
![Page 3: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/3.jpg)
def userForEmail(email: String): Option[User] = ??? def shoeSizeForUser(user: User): Option[Size] = ??? def recommendedShoeStyleForSize(size: Size): Option[ShoeStyle] = ???
def recommendedShoe(email: String): Option[ShoeStyle] = for { user <-‐ userForEmail(email) size <-‐ shoeSizeForUser(user) shoe <-‐ recommendedShoeStyleForSize(size) } yield shoe
recommendedShoe("[email protected]") match { case None => println("No shoe recommendation") case Some(shoe) => println(s"Shoe recommendation: $shoe") }
![Page 4: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/4.jpg)
Future[A]Asynchronous Computation
![Page 5: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/5.jpg)
def userForEmail(email: String): Future[User] = ??? def shoeSizeForUser(user: User): Future[Size] = ??? def recommendedShoeStyleForSize(size: Size): Future[ShoeStyle] = ???
def recommendedShoe(email: String): Future[ShoeStyle] = for { user <-‐ userForEmail(email) size <-‐ shoeSizeForUser(user) shoe <-‐ recommendedShoeStyleForSize(size) } yield shoe
recommendedShoe("[email protected]") onComplete { case Failure(t) => println("Shoe recommendation failed") case Success(shoe) => println(s"Shoe recommendation: $shoe") }
![Page 6: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/6.jpg)
Future[Option[A]]Errors (possible missing values)
+ asynchronous computation
![Page 7: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/7.jpg)
def userForEmail(email: String): Future[Option[User]] = ???
def shoeSizeForUser(userOpt: Option[User]): Future[Option[Size]] = { userOpt match { case None => Future.successful(None) case Some(user) => ??? } }
def recommendedShoeStyleForSize(sizeOpt: Option[Size]): Future[Option[ShoeStyle]] = { sizeOpt match { case None => Future.successful(None) case Some(size) => ??? } }
def recommendedShoe(email: String): Future[Option[ShoeStyle]] = for { user <-‐ userForEmail(email) size <-‐ shoeSizeForUser(user) shoe <-‐ recommendedShoeStyleForSize(size) } yield shoe
recommendedShoe("[email protected]") onComplete { case Failure(t) => println("Shoe recommendation failed") case Success(None) => println("No shoe recommendation") case Success(Some(shoe)) => println(s"Shoe recommendation: $shoe") }
![Page 8: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/8.jpg)
def userForEmail(email: String): Future[Option[User]] = ???
def shoeSizeForUser(userOpt: Option[User]): Future[Option[Size]] = { userOpt match { case None => Future.successful(None) case Some(user) => ??? } }
def recommendedShoeStyleForSize(sizeOpt: Option[Size]): Future[Option[ShoeStyle]] = { sizeOpt match { case None => Future.successful(None) case Some(size) => ??? } }
def recommendedShoe(email: String): Future[Option[ShoeStyle]] = for { user <-‐ userForEmail(email) size <-‐ shoeSizeForUser(user) shoe <-‐ recommendedShoeStyleForSize(size) } yield shoe
recommendedShoe("[email protected]") onComplete { case Failure(t) => println("Shoe recommendation failed") case Success(None) => println("No shoe recommendation") case Success(Some(shoe)) => println(s"Shoe recommendation: $shoe") }
![Page 9: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/9.jpg)
–Dave Thomas
“Every piece of knowledge must have a single, unambiguous, authoritative representation
within a system.”
![Page 10: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/10.jpg)
def flatMap[B](f: A => F[B]): F[B] Given an F[A]:
![Page 11: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/11.jpg)
def flatMap[B](f: A => F[B]): F[B] Given an F[A]:
case class FutureOption[+A](future: Future[Option[A]]) { def flatMap[B](f: A => FutureOption[B]): FutureOption[B] = { val result = future flatMap { case None => Future.successful(None) case Some(opt) => f(opt).future }
FutureOption(result) } }
![Page 12: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/12.jpg)
def userForEmail(email: String): Future[Option[User]] = ??? def shoeSizeForUser(user: User): Future[Option[Size]] = ??? def recommendedShoeStyleForSize(size: Size): Future[Option[ShoeStyle]] = ???
def recommendedShoe(email: String): FutureOption[ShoeStyle] = for { user <-‐ FutureOption(userForEmail(email)) size <-‐ FutureOption(shoeSizeForUser(user)) shoe <-‐ FutureOption(recommendedShoeStyleForSize(size)) } yield shoe
recommendedShoe("[email protected]").future onComplete { case Failure(t) => println("Shoe recommendation failed") case Success(None) => println("No shoe recommendation") case Success(Some(shoe)) => println(s"Shoe recommendation: $shoe") }
![Page 13: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/13.jpg)
def userForEmail(email: String): Future[Option[User]] = ??? def shoeSizeForUser(user: User): Future[Option[Size]] = ??? def recommendedShoeStyleForSize(size: Size): Future[Option[ShoeStyle]] = ???
def recommendedShoe(email: String): FutureOption[ShoeStyle] = for { user <-‐ FutureOption(userForEmail(email)) size <-‐ FutureOption(shoeSizeForUser(user)) shoe <-‐ FutureOption(recommendedShoeStyleForSize(size)) } yield shoe
recommendedShoe("[email protected]").future onComplete { case Failure(t) => println("Shoe recommendation failed") case Success(None) => println("No shoe recommendation") case Success(Some(shoe)) => println(s"Shoe recommendation: $shoe") }
![Page 14: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/14.jpg)
def userForEmail(email: String): Future[Option[User]] = ??? def shoeSizeForUser(user: User): Future[Option[Size]] = ??? def recommendedShoeStyleForSize(size: Size): Future[Option[ShoeStyle]] = ???
def recommendedShoe(email: String): FutureOption[ShoeStyle] = for { user <-‐ FutureOption(userForEmail(email)) size <-‐ FutureOption(shoeSizeForUser(user)) shoe <-‐ FutureOption(recommendedShoeStyleForSize(size)) } yield shoe
recommendedShoe("[email protected]").future onComplete { case Failure(t) => println("Shoe recommendation failed") case Success(None) => println("No shoe recommendation") case Success(Some(shoe)) => println(s"Shoe recommendation: $shoe") }
![Page 15: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/15.jpg)
N*N types =
N2 Implementations?
![Page 16: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/16.jpg)
Monad Transformers To the Rescue
Scalaz
cats
![Page 17: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/17.jpg)
OptionT[F[_], A]
Wraps F[Option[A]]
Works for any F[_] (as long as F[_] is a monad)
Implements passing None through the F[_] effect
e.g. OptionT[Future, A] is a wrapper for Future[Option[A]]
![Page 18: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/18.jpg)
import scala.concurrent.Future import scala.concurrent.ExecutionContext.Implicits.global import scalaz._ import Scalaz._
def userForEmail(email: String): Future[Option[User]] = ??? def shoeSizeForUser(user: User): Future[Option[Size]] = ??? def recommendedShoeStyleForSize(size: Size): Future[Option[ShoeStyle]] = ???
def recommendedShoe(email: String): OptionT[Future, ShoeStyle] = for { user <-‐ OptionT(userForEmail(email)) size <-‐ OptionT(shoeSizeForUser(user)) shoe <-‐ OptionT(recommendedShoeStyleForSize(size)) } yield shoe
recommendedShoe("[email protected]").run onComplete { case Failure(t) => println("Shoe recommendation failed") case Success(None) => println("No shoe recommendation") case Success(Some(shoe)) => println(s"Shoe recommendation: $shoe") }
libraryDependencies += "org.scalaz" %% "scalaz-core" % "7.1.4"
![Page 19: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/19.jpg)
Either[A, B]Errors with a “reason”
![Page 20: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/20.jpg)
Either[A, B]: not nearly as useful as it could be.
In scalaz, use: A \/ B — same as \/[A, B]
In cats, use: A Xor B — same as Xor[A, B]
![Page 21: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/21.jpg)
def userForEmail(email: String): Future[String \/ User] = ??? def shoeSizeForUser(userOpt: String \/ User): Future[String \/ Size] = { userOpt.fold( err => Future.successful(err.left), user => ??? ) }
def recommendedShoeStyleForSize(sizeOpt: String \/ Size): Future[String \/ ShoeStyle] = { sizeOpt.fold( err => Future.successful(err.left), size => ??? ) }
def recommendedShoe(email: String): Future[String \/ ShoeStyle] = for { user <-‐ userForEmail(email) size <-‐ shoeSizeForUser(user) shoe <-‐ recommendedShoeStyleForSize(size) } yield shoe
recommendedShoe("[email protected]") onComplete { case scala.util.Failure(t) => println("Shoe recommendation failed") case scala.util.Success(res) => res.fold( err => println(s"No shoe recommendation, reason: $err"), shoe => println(s"Shoe recommendation: $shoe") ) }
![Page 22: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/22.jpg)
def userForEmail(email: String): Future[String \/ User] = ??? def shoeSizeForUser(userOpt: String \/ User): Future[String \/ Size] = { userOpt.fold( err => Future.successful(err.left), user => ??? ) }
def recommendedShoeStyleForSize(sizeOpt: String \/ Size): Future[String \/ ShoeStyle] = { sizeOpt.fold( err => Future.successful(err.left), size => ??? ) }
def recommendedShoe(email: String): Future[String \/ ShoeStyle] = for { user <-‐ userForEmail(email) size <-‐ shoeSizeForUser(user) shoe <-‐ recommendedShoeStyleForSize(size) } yield shoe
recommendedShoe("[email protected]") onComplete { case scala.util.Failure(t) => println("Shoe recommendation failed") case scala.util.Success(res) => res.fold( err => println(s"No shoe recommendation, reason: $err"), shoe => println(s"Shoe recommendation: $shoe") ) }
![Page 23: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/23.jpg)
def userForEmail(email: String): Future[String \/ User] = ??? def shoeSizeForUser(user: User): Future[String \/ Size] = ??? def recommendedShoeStyleForSize(size: Size): Future[String \/ ShoeStyle] = ???
def recommendedShoe(email: String): EitherT[Future, String, ShoeStyle] = for { user <-‐ EitherT(userForEmail(email)) size <-‐ EitherT(shoeSizeForUser(user)) shoe <-‐ EitherT(recommendedShoeStyleForSize(size)) } yield shoe
recommendedShoe("[email protected]").run onComplete { case scala.util.Failure(t) => println("Shoe recommendation failed") case scala.util.Success(res) => res.fold( err => println(s"No shoe recommendation, reason: $err"), shoe => println(s"Shoe recommendation: $shoe") ) }
![Page 24: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/24.jpg)
Either vs Option
![Page 25: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/25.jpg)
Some(3) \/> "no value" == 3.rightNone \/> "no value" == "no value".left
Converting Option to \/ (Either)
![Page 26: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/26.jpg)
Representing Errors in Play Framework
![Page 27: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/27.jpg)
type Response[A] = EitherT[Future, Result, A]
![Page 28: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/28.jpg)
type Response[A] = EitherT[Future, Result, A]
Response[String] EitherT[Future, Result, String]
![Page 29: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/29.jpg)
type Response[A] = EitherT[Future, Result, A]
Response[String] EitherT[Future, Result, String]
Response[User] EitherT[Future, Result, User]
![Page 30: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/30.jpg)
type Response[A] = EitherT[Future, Result, A]
Response[String] EitherT[Future, Result, String]
Response[User]
Response[UserAndAuthInfo]
EitherT[Future, Result, User]
EitherT[Future, Result, UserAndAuthInfo]
![Page 31: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/31.jpg)
type Response[A] = EitherT[Future, Result, A]
Response[String] EitherT[Future, Result, String]
Response[User]
Response[UserAndAuthInfo]
Response[Result]
EitherT[Future, Result, User]
EitherT[Future, Result, UserAndAuthInfo]
EitherT[Future, Result, Result]
![Page 32: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/32.jpg)
EitherT[Future, Result, Result]
def merge(implicit ev: A =:= B) = fold(left => ev(left), right => right)
Future[Result]
![Page 33: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/33.jpg)
def response(block: => Response[Result]): Action[AnyContent] = Action.async(block.merge)
def response[A](bodyParser: BodyParser[A])(block: Request[A] => Response[Result]): Action[A] = Action.async(bodyParser)(req => block(req).merge)
def response(block: Request[AnyContent] => Response[Result]): Action[AnyContent] = response(BodyParsers.parse.default)(block)
![Page 34: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/34.jpg)
type Response[A] = EitherT[Future, Result, A]
object Response { def fromFuture[A](o: Future[A]): Response[A] = EitherT(o.map(_.right))
def fromFutureOption[A](noValue: => Result)(o: Future[Option[A]]): Response[A] = EitherT(o.map(_ \/> noValue))
def fromFutureEither[A, B](err: A => Result)(o: Future[A \/ B]): Response[B] = EitherT(o.map(_.leftMap(err)))
def fromOption[A](noValue: => Result)(o: Option[A]): Response[A] = EitherT(Future.successful(o \/> noValue))
def fromEither[A, B](e: A => Result)(o: A \/ B): Response[B] = EitherT(Future.successful(o.leftMap(e)))
def fromTry[A](t: Throwable => Result)(o: Try[A]): Response[A] = { val eitherResult = o match { case scala.util.Success(s) => s.right case scala.util.Failure(f) => t(f).left }
EitherT(Future.successful(eitherResult)) } }
![Page 35: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/35.jpg)
def getUserByEmail(email: String): Future[String \/ User] = ??? def getFavouriteProducts(user: User): Future[String \/ Seq[String]] = ???
def productsByEmail(email: String) = response { for { user <-‐ getUserByEmail(email) |> fromFutureEither(s => InternalServerError(s)) products <-‐ getFavouriteProducts(user) |> fromFuture } yield Ok(views.html.productsByEmail(user, products)) }
type Response[A] = EitherT[Future, Result, A]
object Response { def fromFuture[A](o: Future[A]): Response[A] = EitherT(o.map(_.right))
def fromFutureEither[A, B](err: A => Result)(o: Future[A \/ B]): Response[B] = EitherT(o.map(_.leftMap(err))) }
f(a) == a |> f
![Page 36: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/36.jpg)
Domain-specific Errors
![Page 37: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/37.jpg)
sealed trait UserServiceError
private[controllers] case class AuthError(why: String) extends UserServiceError private[controllers] case object ConnectionError extends UserServiceError
object UserServiceError { def authError(why: String): UserServiceError = AuthError(why) val connectionError: UserServiceError = ConnectionError
def fold[A](authError: String => A, connectionError: => A)(u: UserServiceError) = { u match { case AuthError(why) => authError(why) case ConnectionError => connectionError } } }
![Page 38: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/38.jpg)
sealed trait UserServiceError
private[controllers] case class AuthError(why: String) extends UserServiceError private[controllers] case object ConnectionError extends UserServiceError
def getUserByEmail(email: String): Future[UserServiceError \/ User] = ??? def getFavouriteProducts(user: User): Future[String \/ Seq[String]] = ???
val userServiceErrorToResult = UserServiceError.fold( authError = Forbidden(_), connectionError = InternalServerError("foobar") ) _
def productsByEmail(email: String) = response { for { user <-‐ getUserByEmail(email) |> fromFutureEither(userServiceErrorToResult) products <-‐ getFavouriteProducts(user) |> fromFuture } yield Ok(views.html.productsByEmail(user, products)) }
![Page 39: Unsucking Error Handling with Futures](https://reader031.fdocuments.in/reader031/viewer/2022012914/587f0c1a1a28abc26f8b5f39/html5/thumbnails/39.jpg)
Questions?