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

d4s.DynamoConnector.scala Maven / Gradle / Ivy

The newest version!
package d4s

import cats.~>
import d4s.DynamoConnector.DynamoException
import d4s.health.DynamoDBHealthChecker
import d4s.metrics.{MacroMetricDynamoMeter, MacroMetricDynamoTimer}
import d4s.models.DynamoExecution
import d4s.models.query.DynamoRequest
import fs2.Stream
import izumi.functional.bio.{BIOTemporal, F}
import izumi.fundamentals.platform.language.unused
import logstage.LogBIO
import net.playq.metrics.Metrics

trait DynamoConnector[F[+_, +_]] {
  def runUnrecorded[DR <: DynamoRequest, A](q: DynamoExecution[DR, _, A]): F[Throwable, A]
  def runUnrecorded[DR <: DynamoRequest, A](q: DynamoExecution.Streamed[DR, _, A]): Stream[F[Throwable, ?], A]

  def run[DR <: DynamoRequest, Dec, A](label: String)(q: DynamoExecution[DR, Dec, A])(implicit
                                                                                      macroTimeSaver: MacroMetricDynamoTimer[label.type],
                                                                                      macroMeterSaver: MacroMetricDynamoMeter[label.type]): F[DynamoException, A]

  def runStreamed[DR <: DynamoRequest, Dec, A](label: String)(q: DynamoExecution.Streamed[DR, Dec, A])(
    implicit
    macroTimeSaver: MacroMetricDynamoTimer[label.type],
    macroMeterSaver: MacroMetricDynamoMeter[label.type]
  ): Stream[F[DynamoException, ?], A]
}

object DynamoConnector {
  final case class DynamoException(queryName: String, cause: Throwable)
    extends RuntimeException(s"Dynamo query `$queryName` failed due to error=${cause.getMessage}", cause)

  final class Impl[F[+_, +_]: BIOTemporal](
    interpreter: DynamoInterpreter[F],
    @unused dynamoDBHealthChecker: DynamoDBHealthChecker[F],
    @unused dynamoDDLService: DynamoDDLService[F],
    metrics: Metrics[F],
    log: LogBIO[F]
  ) extends DynamoConnector[F] {

    override def runUnrecorded[DR <: DynamoRequest, A](q: DynamoExecution[DR, _, A]): F[Throwable, A] =
      runUnrecordedImpl(q)

    override def runUnrecorded[DR <: DynamoRequest, A](q: DynamoExecution.Streamed[DR, _, A]): Stream[F[Throwable, ?], A] =
      runUnrecordedImpl(q)

    private[this] def runUnrecordedImpl[DR <: DynamoRequest, Dec, Out[_[_, _]]](q: DynamoExecution.Dependent[DR, Dec, Out]): Out[F] = {
      q.executionStrategy(q.dynamoQuery)(DynamoExecutionContext(F, interpreter))
    }

    override def run[DR <: DynamoRequest, Dec, A](label: String)(q: DynamoExecution[DR, Dec, A])(
      implicit
      macroTimeSaver: MacroMetricDynamoTimer[label.type],
      macroMeterSaver: MacroMetricDynamoMeter[label.type]
    ): F[DynamoException, A] = {
      recordMetrics(label) {
        runUnrecorded(q)
      }.leftMap(DynamoException(label, _))
    }

    override def runStreamed[DR <: DynamoRequest, Dec, A](label: String)(q: DynamoExecution.Streamed[DR, Dec, A])(
      implicit
      macroTimeSaver: MacroMetricDynamoTimer[label.type],
      macroMeterSaver: MacroMetricDynamoMeter[label.type]
    ): Stream[F[DynamoException, ?], A] = {
      val recordStreamPage = Lambda[F[Throwable, ?] ~> F[Throwable, ?]] {
        recordMetrics(label)(_)
      }

      q.executionStrategy(q.dynamoQuery)(DynamoExecutionContext(F, interpreter, recordStreamPage))
        .translate(Lambda[F[Throwable, ?] ~> F[DynamoException, ?]] {
          _.leftMap(DynamoException(label, _))
        })
    }

    private[this] def recordMetrics[A](label: String)(f: F[Throwable, A])(implicit
                                                                          macroTimeSaver: MacroMetricDynamoTimer[label.type],
                                                                          macroMeterSaver: MacroMetricDynamoMeter[label.type]): F[Throwable, A] = {
      metrics.withTimer(label) {
        f.tapError {
          exception =>
            metrics.mark(label) *>
            metrics.mark("dynamo:query-exception") *>
            log.error(s"Uncaught DynamoDB Exception $exception")
        }
      }
    }

  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy