Skip to content

Commit

Permalink
Add invalidation for the schema-list cache (close #215)
Browse files Browse the repository at this point in the history
  • Loading branch information
voropaevp committed Nov 18, 2022
1 parent 1f4a195 commit 85ae934
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ final case class Resolver[F[_]](repos: List[Registry], cache: Option[ResolverCac
def listSchemasResult(
vendor: String,
name: String,
model: Int
model: Int,
mustIncludeKey: Option[SchemaKey] = None
)(implicit
F: Monad[F],
L: RegistryLookup[F],
Expand Down Expand Up @@ -151,7 +152,11 @@ final case class Resolver[F[_]](repos: List[Registry], cache: Option[ResolverCac

getSchemaListFromCache(vendor, name, model).flatMap {
case Some(TimestampedItem(Right(schemaList), timestamp)) =>
Monad[F].pure(Right(ResolverResult.Cached((vendor, name, model), schemaList, timestamp)))
if (mustIncludeKey.forall(schemaList.schemas.contains))
Monad[F].pure(Right(ResolverResult.Cached((vendor, name, model), schemaList, timestamp)))
else
traverseRepos[F, SchemaList](get, prioritize(vendor, allRepos.toList), Map.empty)
.flatMap(handleAfterFetch)
case Some(TimestampedItem(Left(failures), _)) =>
retryCached[F, SchemaList](get, vendor)(failures)
.flatMap(handleAfterFetch)
Expand All @@ -177,6 +182,19 @@ final case class Resolver[F[_]](repos: List[Registry], cache: Option[ResolverCac
): F[Either[ResolutionError, SchemaList]] =
listSchemasResult(vendor, name, model).map(_.map(_.value))

/**
* Vendor, name, model are extracted from supplied schema key to call on the `listSchemas`. The important difference
* from `listSchemas` is that it would invalidate cache, if returned list did not contain SchemaKey supplied in
* argument. Making it a safer option is latest schema bound is known.
*/
def listSchemasLike(schemaKey: SchemaKey)(implicit
F: Monad[F],
L: RegistryLookup[F],
C: Clock[F]
): F[Either[ResolutionError, SchemaList]] =
listSchemasResult(schemaKey.vendor, schemaKey.name, schemaKey.version.model, Some(schemaKey))
.map(_.map(_.value))

/** Get list of full self-describing schemas available on Iglu Server for particular vendor/name pair */
def fetchSchemas(
vendor: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@
*/
package com.snowplowanalytics.iglu.client.resolver

import com.snowplowanalytics.iglu.core.SchemaList

import java.time.Instant
import java.net.URI

import scala.collection.immutable.SortedMap

// Cats
import cats.Id
import cats.effect.IO
import cats.implicits._
import cats.syntax.all._

// circe
import io.circe.Json
Expand Down Expand Up @@ -70,6 +71,7 @@ class ResolverSpec extends Specification with DataTables with ValidatedMatchers
a Resolver should accumulate errors from all repositories $e8
we can construct a Resolver from a valid resolver 1-0-2 configuration JSON $e10
a Resolver should cache SchemaLists with different models separately $e11
a Resolver should use schemaKey provided in SchemaListLike for result validation $e12
"""

import ResolverSpec._
Expand Down Expand Up @@ -157,7 +159,7 @@ class ResolverSpec extends Specification with DataTables with ValidatedMatchers
SortedMap(
"Iglu Client Embedded" -> LookupHistory(Set(RegistryError.NotFound), 1, SpecHelpers.now),
"Iglu Test Embedded" -> LookupHistory(
Set(RegistryError.RepoFailure("ParsingFailure: exhausted input")),
Set(RegistryError.NotFound),
1,
SpecHelpers.now
)
Expand Down Expand Up @@ -408,4 +410,47 @@ class ResolverSpec extends Specification with DataTables with ValidatedMatchers
case _ => ko("Unexpected result for two consequent listSchemas")
}
}

def e12 = {
val IgluCentralServer = Registry.Http(
Registry.Config("Iglu Central EU1", 0, List("com.snowplowanalytics")),
Registry
.HttpConnection(URI.create("https://com-iglucentral-eu1-prod.iglu.snplow.net/api"), None)
)

val schema100 = SchemaKey(
"com.snowplowanalytics.snowplow",
"link_click",
"jsonschema",
SchemaVer.Full(1, 0, 0)
)
val schema101 = SchemaKey(
"com.snowplowanalytics.snowplow",
"link_click",
"jsonschema",
SchemaVer.Full(1, 0, 1)
)

val resolverRef = Resolver.init[Id](10, None, IgluCentralServer)
val resolver = resolverRef.map(res =>
new Resolver(
res.repos,
res.cache.flatMap { c =>
c.putSchemaList(
"com.snowplowanalytics.snowplow",
"link_click",
1,
SchemaList(List(schema100)).asRight
)
c.some
}
)
)

val resultOne = resolver.listSchemasLike(schema100)
val resultTwo = resolver.listSchemasLike(schema101)

resultOne must beRight(SchemaList(List(schema100)))
resultTwo must beRight(SchemaList(List(schema100, schema101)))
}
}

0 comments on commit 85ae934

Please sign in to comment.