如何摆脱"额外" Akka Stream Flow阶段的未来?

时间:2018-04-24 16:14:35

标签: scala akka akka-stream

我正在与Akka Streams合作并尝试使用Flow阶段来最有效地描述整个图表。在某些阶段,我通过ask模式向演员发送消息。

当然,当我使用ask模式时,我需要使用mapTo才能获得预期的类型以便进一步处理。

以下是一个例子:

val runnableGraph = Source.single(CheckEntity(entity))
  .map { check =>
    (postgresActor ? check)
      .mapTo[CheckEntityResult]
      .map {
        case failure: PostgresFailure => Left(failure.message)
        case pEntity: PEntity => Right(check)
    }
  }
  .map {
    _.map {
      case Left(msg) => Future(Left(msg))
      case Right(check) =>
        (redisActor ? pEntity)
          .mapTo[CheckEntityResult]
          .map {
            case failure: RedisFailure => Left(failure.message)
            case rEntity: REntity => Right(rEntity)
          }
    }
  }
  .toMat(Sink.head)(Keep.right)

//The result's type is Future[Future[Either[String, Entity]]]
val futureResult = runnableGraph.run()

如何摆脱各阶段之间的嵌套Future

2 个答案:

答案 0 :(得分:2)

通过流传播CheckEntity元素更容易的一个想法是更改CheckEntityResult类以包含相应的CheckEntity实例。这看起来像这样:

abstract class CheckEntityResult(entity: CheckEntity) extends Entity

case class PEntity(entity: CheckEntity) extends CheckEntityResult(entity)
case class PostgresFailure(entity: CheckEntity, message: String) extends CheckEntityResult(entity)

case class REntity(entity: CheckEntity) extends CheckEntityResult(entity)
case class RedisFailure(entity: CheckEntity, message: String) extends CheckEntityResult(entity)

然后,在调整actor以处理这些消息之后,您可以使用Source # askmapAsync(根据需要调整并行度级别)与actor进行交互并避免嵌套{{1在物化值中:

Future

答案 1 :(得分:1)

您可以考虑将您的actor查询转换为Flow以及mapAsync(具有适当的并行性):

val postgresCheck = (check: CheckEntity) =>
    (postgresActor ? check).mapTo[CheckEntityResult]
      .map {
        case failure: PostgresFailure => Left(failure.message)
        case pEntity: PEntity => Right(check)
      }

val redisCheck = (e: Either[String, CheckEntityResult]) => e match {
    case Left(msg) => Future(Left(msg))
    case Right(checkResult) =>
      (redisActor ? checkResult).mapTo[CheckEntityResult]
        .map {
          case failure: RedisFailure => Left(failure.message)
          case rEntity: REntity => Right(rEntity)
        }
  }

val postgresCheckFlow = (parallelism: Int) =>
    Flow[CheckEntity]
      .mapAsync[Either[String, CheckEntityResult]](parallelism)(postgresCheck)

val redisCheckFlow = (parallelism: Int) =>
    Flow[Either[String, CheckEntityResult]]
      .mapAsync[Either[String, CheckEntityResult]](parallelism)(redisCheck)

使用转换后的流程,您的runnableGraph可以如下组合,结果类型为Future[Either[]]

val runnableGraph = Source.single(CheckEntity(entity))
  .via(postgresCheckFlow(parallelism))
  .via(redisCheckFlow(parallelism))
  ...