All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nl.vroste.zio.kinesis.client.dynamicconsumer.fake.DynamicConsumerFake.scala Maven / Gradle / Ivy

The newest version!
package nl.vroste.zio.kinesis.client.dynamicconsumer.fake

import nl.vroste.zio.kinesis.client.dynamicconsumer.DynamicConsumer.{ Checkpointer, Record }
import nl.vroste.zio.kinesis.client.dynamicconsumer.{ DynamicConsumer, ExtendedSequenceNumber, SchedulerConfig }
import nl.vroste.zio.kinesis.client.serde.{ Deserializer, Serializer }
import software.amazon.awssdk.services.kinesis.model.EncryptionType
import software.amazon.kinesis.common.InitialPositionInStreamExtended
import zio.stream.ZStream
import zio.{ Clock, _ }

private[client] class DynamicConsumerFake(
  shards: ZStream[Any, Throwable, (String, ZStream[Any, Throwable, Chunk[Byte]])],
  refCheckpointedList: Ref[Seq[Record[Any]]]
) extends DynamicConsumer {
  override def shardedStream[R, T](
    streamName: String,
    applicationName: String,
    deserializer: Deserializer[R, T],
    requestShutdown: UIO[Unit],
    initialPosition: InitialPositionInStreamExtended,
    leaseTableName: Option[String],
    metricsNamespace: Option[String],
    workerIdentifier: String,
    maxShardBufferSize: Int,
    configureKcl: SchedulerConfig => SchedulerConfig
  ): ZStream[
    R,
    Throwable,
    (String, ZStream[Any, Throwable, Record[T]], DynamicConsumer.Checkpointer)
  ] = {
    def record(shardName: String, i: Long, recData: T): UIO[Record[T]] =
      for {
        dateTime <- Clock.currentDateTime
      } yield new Record[T](
        sequenceNumber = s"$i",
        approximateArrivalTimestamp = dateTime.toInstant,
        data = recData,
        partitionKey = s"${shardName}_$i",
        encryptionType = EncryptionType.NONE,
        subSequenceNumber = None,
        explicitHashKey = None,
        aggregated = false,
        shardId = shardName
      )

    shards.flatMap { case (shardName, stream) =>
      ZStream.fromZIO {
        ZIO.environment[R].flatMap { env =>
          CheckpointerFake.make(refCheckpointedList).map { checkpointer =>
            (
              shardName,
              stream.zipWithIndex.mapZIO { case (byteBuffer, i) =>
                deserializer.deserialize(byteBuffer).flatMap(record(shardName, i, _)).provideEnvironment(env)
              },
              checkpointer
            )
          }
        }
      }
    }

  }
}

object CheckpointerFake {

  def make(refCheckpointedList: Ref[Seq[Record[Any]]]): Task[Checkpointer] =
    for {
      latestStaged <- Ref.make[Option[Record[_]]](None)
    } yield new DynamicConsumer.Checkpointer {
      override private[client] def peek: UIO[Option[ExtendedSequenceNumber]] =
        latestStaged.get
          .map(_.map(r => ExtendedSequenceNumber(r.sequenceNumber, r.subSequenceNumber)))

      override def stage(r: Record[_]): UIO[Unit] = latestStaged.set(Some(r))

      override def checkpoint: ZIO[Any, Throwable, Unit] =
        latestStaged.get.flatMap {
          case Some(record) =>
            refCheckpointedList.update(seq => seq :+ record) *>
              latestStaged.update {
                case Some(r) if r == record => None
                case r                      => r // A newer record may have been staged by now
              }
          case None         => ZIO.unit
        }
    }
}

object DynamicConsumerFake {

  /**
   * A constructor for a fake shard, for use with the `DynamicConsumer.fake` ZLayer function. It takes a list of
   * `List[T]` and produces a ZStream of fake shards from it.
   * @param serializer
   *   A `Serializer` used to convert elements to the Chunk[Byte] type expected by `DynamicConsumer`
   * @param lists
   *   list of shards - each shard is represented by a List of `T`
   * @tparam R
   *   Environment for `Serializer`
   * @tparam T
   *   Type of the list element
   * @return
   *   A ZStream of fake shard with a generated shard name of the form `shardN`, where `N` is a zero based index
   * @see
   *   `DynamicConsumer.fake`
   */
  def shardsFromIterables[R, T](
    serializer: Serializer[R, T],
    lists: List[T]*
  ): ZStream[Any, Nothing, (String, ZStream[R, Throwable, Chunk[Byte]])] = {
    val listOfShards = lists.zipWithIndex.map { case (xs, i) =>
      (s"shard$i", ZStream.fromIterable(xs).mapZIO(serializer.serialize))
    }
    ZStream.fromIterable(listOfShards)
  }

  /**
   * A constructor for a fake shard, for use with the `DynamicConsumer.fake` ZLayer function. It takes a list ZStream of
   * type `T` and produces a ZStream of fake shards from it.
   * @param serializer
   *   A `Serializer` used to convert elements to the Chunk[Byte] type expected by `DynamicConsumer`
   * @param streams
   *   list of shards - each shard is represented by a ZStream of `T`
   * @tparam R
   *   Environment for `Serializer`
   * @tparam T
   *   Type of the ZStream element
   * @return
   *   A ZStream of fake shard with a generated shard name of the form `shardN`, where `N` is a zero based index
   * @see
   *   `DynamicConsumer.fake`
   */
  def shardsFromStreams[R, T](
    serializer: Serializer[R, T],
    streams: ZStream[R, Throwable, T]*
  ): ZStream[Any, Nothing, (String, ZStream[R, Throwable, Chunk[Byte]])] = {
    val listOfShards = streams.zipWithIndex.map { case (stream, i) =>
      (s"shard$i", stream.mapZIO(serializer.serialize))
    }
    ZStream.fromIterable(listOfShards)
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy