Выдает ошибку с помощью scala и spray

Я пытаюсь создать простое приложение CRUD с помощью scala и спрей-маршрутизации. У меня следующий маршрут:

override def receive = runRoute {
    path("entities" / LongNumber) { id =>
      get {
        produce(instanceOf[MyEntity]) {
          func => ctx => heavyLookupById(id, func)
        }
    }
}

Я написал это согласно официальной документации http://spray.io/documentation/1.2.2/spray-routing/marshalling-directives/produce/

MyEntity выглядит следующим образом (на самом деле не имеет значения):

case class MyEntity(text: String, id: Option[Long])

И у меня есть следующий объект поддержки json

object MyJsonSupport extends DefaultJsonProtocol with SprayJsonSupport {
    implicit val format = jsonFormat2(MyEntity)
}

Функция "heavyLookupById" содержит некоторые тяжелые блокирующие вычисления (предположим, запросы к базе данных или http-запросы), и из-за этого мне приходится иметь дело с будущим scala:

def heavyLookupById(id: Long, func: MyEntity => Unit) = {
   // ... heavy computations
   future onSuccess { case x => func(x) }
}

Но что мне делать, если мое будущее рушится? Я хочу ответить чем-то вроде неверного запроса (400) или не найденных (404) ошибок HTTP, но как это сделать? Если я не вызываю "func" внутри "heavyLookupById" - запрос просто зависает - я считаю, что по умолчанию тайм-аут сервера завершится ошибкой (1 минута или около того).


person pkozlov    schedule 07.07.2015    source источник


Ответы (1)


У вас есть RequestContext (ctx), поэтому вы можете вызывать reject, failWith или любые другие методы, доступные в RequestContext.

  val route = path("entities" / LongNumber) { id =>
    get {
      produce(instanceOf[MyEntity]) {
        func => ctx => heavyLookupById(id, func, ctx)
      }
    }
  }

  def heavyLookupById(id: Long, func: MyEntity => Unit, ctx: RequestContext) = {
    // ... heavy computations
    val future = Future.successful(MyEntity("Hello", Some(1)))
    future.onComplete {
      case Success(value) => func(value)
      case Failure(ex) => ctx.failWith(ex)
    }

  }

Лично я предпочитаю handleWith, а не производить, я считаю немного легче читать.

Также в случае сбоя спрей просто вернет 500, которые вы можете настроить с помощью обработчики исключений.

  def heavyLookupById(id: Long) = {
    // ... heavy computations
    Future.successful(MyEntity("Hello", Some(1)))
  }


  val route = path("entities" / LongNumber) { id =>
    get {
      handleWith(heavyLookupById)
    }
  }
person mericano1    schedule 08.07.2015
comment
Спасибо. Теперь мне ясно, как правильно использовать продукцию. - person pkozlov; 09.07.2015