Scala Akka流更改第三方流/级的返回类型

Scala Akka流更改第三方流/级的返回类型,scala,akka-stream,akka-http,Scala,Akka Stream,Akka Http,我有一个从sqs读取、写入另一个系统然后从sqs删除的图形。为了从sqs中删除,我需要SqsMessage对象上的收据句柄 在Http流的情况下,流的签名允许我说哪个类型从流的下游发出 Flow[(HttpRequest, T), (Try[HttpResponse], T), HostConnectionPool] 在这种情况下,我可以将T设置为SqsMessage,并且我仍然拥有所需的所有数据 然而,一些连接器,例如google cloud pub sub,会发出一个完全无用的(对我来说)

我有一个从sqs读取、写入另一个系统然后从sqs删除的图形。为了从sqs中删除,我需要SqsMessage对象上的收据句柄

在Http流的情况下,流的签名允许我说哪个类型从流的下游发出

Flow[(HttpRequest, T), (Try[HttpResponse], T), HostConnectionPool]
在这种情况下,我可以将T设置为SqsMessage,并且我仍然拥有所需的所有数据

然而,一些连接器,例如google cloud pub sub,会发出一个完全无用的(对我来说)pub sub id

在发布子流的下游,我需要能够访问发布子流之前的sqs消息id

在不重写发布子连接器的情况下解决此问题的最佳方法是什么

从概念上讲,我想要这样的东西:

Flow[SqsMessage] //i have my data at this point
within(
.map(toPubSubMessage)
.via(pubSub))

... from here i have the same type i had before within however it still behaves like a linear graph with back pressure etc

您可以使用PassThrough集成模式。 作为使用示例,请查看->Class
akka.kafka.scaladsl.Producer
->Mehtod def
low[K,V,PassThrough]

package my.package

import java.util.concurrent.atomic.AtomicInteger

import scala.concurrent.Future
import scala.util.{Failure, Success, Try}

import akka.stream._
import akka.stream.ActorAttributes.SupervisionStrategy
import akka.stream.stage._

final case class Message[V, PassThrough](record: V, passThrough: PassThrough)

final case class Result[R, PassThrough](result: R, message: PassThrough)

class PathThroughStage[R, V, PassThrough]
  extends GraphStage[FlowShape[Message[V, PassThrough], Future[Result[R, PassThrough]]]] {

  private val in = Inlet[Message[V, PassThrough]]("messages")
  private val out = Outlet[Result[R, PassThrough]]("result")
  override val shape = FlowShape(in, out)

  override protected def createLogic(inheritedAttributes: Attributes) = {
    val logic = new GraphStageLogic(shape) with StageLogging {
      lazy val decider = inheritedAttributes.get[SupervisionStrategy]
        .map(_.decider)
        .getOrElse(Supervision.stoppingDecider)
      val awaitingConfirmation = new AtomicInteger(0)
      @volatile var inIsClosed = false

      var completionState: Option[Try[Unit]] = None

      override protected def logSource: Class[_] = classOf[PathThroughStage[R, V, PassThrough]]

      def checkForCompletion() = {
        if (isClosed(in) && awaitingConfirmation.get == 0) {
          completionState match {
            case Some(Success(_)) => completeStage()
            case Some(Failure(ex)) => failStage(ex)
            case None => failStage(new IllegalStateException("Stage completed, but there is no info about status"))
          }
        }
      }

      val checkForCompletionCB = getAsyncCallback[Unit] { _ =>
        checkForCompletion()
      }

      val failStageCb = getAsyncCallback[Throwable] { ex =>
        failStage(ex)
      }

      setHandler(out, new OutHandler {
        override def onPull() = {
          tryPull(in)
        }
      })

      setHandler(in, new InHandler {
        override def onPush() = {
          val msg = grab(in)
          val f = Future[Result[R, PassThrough]] {
            try {
              Result(// TODO YOUR logic
                msg.record,
                msg.passThrough)
            } catch {
              case exception: Exception =>
                decider(exception) match {
                  case Supervision.Stop =>
                    failStageCb.invoke(exception)
                  case _ =>
                    Result(exception, msg.passThrough)
                }
            }

            if (awaitingConfirmation.decrementAndGet() == 0 && inIsClosed) checkForCompletionCB.invoke(())
          }
          awaitingConfirmation.incrementAndGet()
          push(out, f)
        }

        override def onUpstreamFinish() = {
          inIsClosed = true
          completionState = Some(Success(()))
          checkForCompletion()
        }

        override def onUpstreamFailure(ex: Throwable) = {
          inIsClosed = true
          completionState = Some(Failure(ex))
          checkForCompletion()
        }
      })

      override def postStop() = {
        log.debug("Stage completed")
        super.postStop()
      }
    }
    logic
  }
}
因此,只需使用
PassThrough
元素实现您自己的阶段,例如
akka.kafka.internal.ProducerStage[K,V,PassThrough]

package my.package

import java.util.concurrent.atomic.AtomicInteger

import scala.concurrent.Future
import scala.util.{Failure, Success, Try}

import akka.stream._
import akka.stream.ActorAttributes.SupervisionStrategy
import akka.stream.stage._

final case class Message[V, PassThrough](record: V, passThrough: PassThrough)

final case class Result[R, PassThrough](result: R, message: PassThrough)

class PathThroughStage[R, V, PassThrough]
  extends GraphStage[FlowShape[Message[V, PassThrough], Future[Result[R, PassThrough]]]] {

  private val in = Inlet[Message[V, PassThrough]]("messages")
  private val out = Outlet[Result[R, PassThrough]]("result")
  override val shape = FlowShape(in, out)

  override protected def createLogic(inheritedAttributes: Attributes) = {
    val logic = new GraphStageLogic(shape) with StageLogging {
      lazy val decider = inheritedAttributes.get[SupervisionStrategy]
        .map(_.decider)
        .getOrElse(Supervision.stoppingDecider)
      val awaitingConfirmation = new AtomicInteger(0)
      @volatile var inIsClosed = false

      var completionState: Option[Try[Unit]] = None

      override protected def logSource: Class[_] = classOf[PathThroughStage[R, V, PassThrough]]

      def checkForCompletion() = {
        if (isClosed(in) && awaitingConfirmation.get == 0) {
          completionState match {
            case Some(Success(_)) => completeStage()
            case Some(Failure(ex)) => failStage(ex)
            case None => failStage(new IllegalStateException("Stage completed, but there is no info about status"))
          }
        }
      }

      val checkForCompletionCB = getAsyncCallback[Unit] { _ =>
        checkForCompletion()
      }

      val failStageCb = getAsyncCallback[Throwable] { ex =>
        failStage(ex)
      }

      setHandler(out, new OutHandler {
        override def onPull() = {
          tryPull(in)
        }
      })

      setHandler(in, new InHandler {
        override def onPush() = {
          val msg = grab(in)
          val f = Future[Result[R, PassThrough]] {
            try {
              Result(// TODO YOUR logic
                msg.record,
                msg.passThrough)
            } catch {
              case exception: Exception =>
                decider(exception) match {
                  case Supervision.Stop =>
                    failStageCb.invoke(exception)
                  case _ =>
                    Result(exception, msg.passThrough)
                }
            }

            if (awaitingConfirmation.decrementAndGet() == 0 && inIsClosed) checkForCompletionCB.invoke(())
          }
          awaitingConfirmation.incrementAndGet()
          push(out, f)
        }

        override def onUpstreamFinish() = {
          inIsClosed = true
          completionState = Some(Success(()))
          checkForCompletion()
        }

        override def onUpstreamFailure(ex: Throwable) = {
          inIsClosed = true
          completionState = Some(Failure(ex))
          checkForCompletion()
        }
      })

      override def postStop() = {
        log.debug("Stage completed")
        super.postStop()
      }
    }
    logic
  }
}