Scala, ZIO - конвертируйте будущее в ZIO или ZIO в будущее. Является ли это возможным?

Я создал две версии своего сервиса. Первый использует Futures, другой использует ZIO как эффект.

У меня есть простой метод, который использует Future в качестве результата:

def get(id: String)(implicit executionContext: ExecutionContext): Future[Data]

У меня также есть другая версия, в которой используется ZIO[SomeEnv, SomeError, Data]:

def get(id: String): ZIO[SomeEnv, SomeError, Data]

Теперь мне нужно создать какой-то адаптер, который будет возвращать данные из той или иной версии:

def returnDataFromServiceVersion(version: Int) : ??? = {
   if(version == 1) futureService.get(...)
   else zioService.get(...)
}

Проблема здесь в возвращаемом типе. Я не знаю, как преобразовать ZIO в будущее или Future в ZIO, чтобы иметь общий тип возврата. Я пробовал использовать ZIO.fromFuture{...} или toFuture(), но это не помогло. У меня вопрос - как создать этот returnDataFromServiceVersion метод, чтобы использовать его с обеими службами? Здесь мне нужен общий возвращаемый тип.

А может есть другой способ решить эту проблему?


person Developus    schedule 01.07.2020    source источник
comment
В остальной части кода используется ZIO или Future? Какие ошибки вы получили при попытке сделать fromFuture?   -  person paulpdaniels    schedule 01.07.2020
comment
Остальные - это маршруты akka, и я только позвонил в эти службы, чтобы завершить   -  person Developus    schedule 01.07.2020


Ответы (2)


Если я правильно понимаю, что вам нужно, это обычный ZIO тип, который будет выглядеть так ZIO[SomeEnv, SomeError, Data]

Этого можно достичь с помощью ZIO.fromFuture и сопоставления Throwable (который является Future типом сбоя) с вашим SomeError:

  case class Data(data: String)
  case class SomeEnv(env: String)
  case class SomeError(err: String)

  object SomeError {
    def fromThrowable(throwable: Throwable) = SomeError(throwable.toString)
  }

  def getFuture(id: String)(implicit executionContext: ExecutionContext): Future[Data] = ???
  def getZIO(id: String): ZIO[SomeEnv, SomeError, Data] = ???

  def returnDataFromServiceVersion(version: Int): ZIO[SomeEnv, SomeError, Data] =
    if (version == 1)
      ZIO
        .fromFuture(executionContext => getFuture("id")(executionContext))
        .mapError(SomeError.fromThrowable)
    else
      getZIO("id")
person energi    schedule 01.07.2020
comment
.mapError(SomeError.fromThrowable) это нужно? Я не могу использовать здесь fromThrowable метод - person Developus; 01.07.2020
comment
Ах, моя беда. Это нестандартный метод. Я добавил недостающий код к исходному ответу. - person energi; 01.07.2020

Вы должны решить, возвращает ли ваша функция Future или ZIO, и это не может зависеть от значения времени выполнения, такого как version в вашем фрагменте (если, конечно, вы не определите тип возвращаемого значения как AnyRef - не очень полезно).
Если остальная часть вашего программа основана на Futures, но вы хотели бы начать внедрять ZIO в некоторые службы, вы можете сделать это, выполнив свои эффекты самостоятельно, используя runtime.unsafeRun(effect):

val runtime = Runtime.default

def returnDataFromServiceVersion(version: Int): Future[Data] = {
  runtime.unsafeRunToFuture(
    zioService.get(...)
  )
}

Для получения дополнительных сведений см. Running Effects в официальной документации ZIO.

person zagyi    schedule 01.07.2020
comment
Я думаю, runtime.unsafeRunToFuture это то, что вы ищете. В настоящее время это заставит этот метод блокировать контекст выполнения. - person paulpdaniels; 01.07.2020
comment
Спасибо за исправление @paulpdaniels! Я обновил ответ. - person zagyi; 01.07.2020