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

com.snowplowanalytics.iglu.client.resolver.LookupHistory.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2014-2023 Snowplow Analytics Ltd. All rights reserved.
 *
 * This program is licensed to you under the Apache License Version 2.0,
 * and you may not use this file except in compliance with the Apache License Version 2.0.
 * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the Apache License Version 2.0 is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
 */
package com.snowplowanalytics.iglu.client.resolver

import java.time.Instant

import cats.Semigroup
import cats.instances.set._
import cats.syntax.semigroup._

import io.circe.{Decoder, Encoder, Json}
import io.circe.syntax._

import registries.RegistryError

/**
 * Helper class responsible for aggregating repository lookup errors
 * Using to aggregate all errors for single schema for single repo during all retries
 *
 * @param errors set of all errors happened during all attempts
 * @param attempts amount of undertaken attempts, *since last TTL invalidation*
 * @param lastAttempt when Resolver tried to fetch it last time
 */
case class LookupHistory(
  errors: Set[RegistryError],
  attempts: Int,
  lastAttempt: Instant
) {
  def incrementAttempt: LookupHistory =
    LookupHistory(errors, attempts + 1, lastAttempt)
}

object LookupHistory {

  val MaxErrors = 32

  /** Semigroup instance helping to aggregate repository errors */
  implicit val lookupHistorySemigroup: Semigroup[LookupHistory] =
    new Semigroup[LookupHistory] {
      override def combine(a: LookupHistory, b: LookupHistory): LookupHistory =
        LookupHistory(
          (a.errors |+| b.errors).take(MaxErrors),
          a.attempts.max(b.attempts),
          maxInstant(a.lastAttempt, b.lastAttempt)
        )
    }

  implicit val lookupHistoryEncoder: Encoder[LookupHistory] = Encoder.instance { history =>
    Json.obj(
      "errors"      := history.errors.asJson,
      "attempts"    := history.attempts.asJson,
      "lastAttempt" := history.lastAttempt.asJson
    )
  }

  implicit val lookupHistoryDecoder: Decoder[LookupHistory] = Decoder.instance { cursor =>
    for {
      errors   <- cursor.downField("errors").as[Set[RegistryError]]
      attempts <- cursor.downField("attempts").as[Int]
      last     <- cursor.downField("lastAttempt").as[Instant]
    } yield LookupHistory(errors, attempts, last)
  }

  private def maxInstant(a: Instant, b: Instant): Instant =
    if (a.isAfter(b)) a else b
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy