Почему Akka HTTP Routing перехватывает мое исключение?

Учитывая этот код

def leaderboardPost(name: Option[String]): Route =
  post {
    logRequest("leaderboard", Logging.DebugLevel) {
      handleRejections(postBodyRejections) {
        entity(as[LeaderboardPostRequest]) { leaderboard =>
          try {
            complete(leaderboardCreate(Some(leaderboard.name), Some(leaderboard.kind)))
          } catch {
            case cause: DuplicateIDException =>
              logger.error(cause)
              complete(cause.response)
            case cause: UnknownKindException =>
              logger.warn(cause)
              complete(cause.response)
            case cause: Throwable =>
              logger.error(cause)
              complete(HttpResponse(InternalServerError, entity = s"Exception thrown from LeaderboardPost: ${cause.getMessage}"))
          }
        }
      }
    }
  }

когда leaderboardCreate бросает UnknownKindException код маршрутизации ловит его и преобразует в Completing with 500 Internal Server Error response. To change default exception handling behavior, provide a custom ExceptionHandler.

Пока я смотрю на создание пользовательского ExceptionHandler, я не понимаю, зачем мне это нужно. Мой код должен поймать его и вернуть complete(cause.response) вместо. Как Akka HTTP перехватывает исключение до того, как мой код делает?

1 ответ

Решение

Согласно моему пониманию, это происходит потому, что leaderboardCreate на самом деле не выполняется синхронно с complete звоните, как вы могли ожидать. complete метод возвращает StandardRoute который простирается от Route определяется как:

type Route = RequestContext ⇒ Future[RouteResult]

Другими словами, "маршрут" - это функция от контекста к Future (из RouteResult). И если вы посмотрите на complete определение, это просто:

def complete(m: ⇒ ToResponseMarshallable): StandardRoute =
  StandardRoute(_.complete(m))

Обратите внимание до ToResponseMarshallable, Это передача параметра по имени, который фактически превращает его в ленивую оценку.

Другими словами, все ваши try/catch обертки очень маленький (и без исключения) код построения StandardRoute это фиксирует вашу логику как ленивое значение, но не выполнение самой логики. Вот почему вам нужен пользовательский ExceptionHandler, который вы (или, скорее, Akka) действительно можете поместить в цепочку обработчиков ошибок для Future когда он будет запущен.

Другие вопросы по тегам