diff --git a/graph-commons/src/main/scala/io/renku/logging/ExecutionTimeRecorder.scala b/graph-commons/src/main/scala/io/renku/logging/ExecutionTimeRecorder.scala index cc3fa95448..f81d86ed0f 100644 --- a/graph-commons/src/main/scala/io/renku/logging/ExecutionTimeRecorder.scala +++ b/graph-commons/src/main/scala/io/renku/logging/ExecutionTimeRecorder.scala @@ -39,15 +39,15 @@ abstract class ExecutionTimeRecorder[F[_]](threshold: ElapsedTime) { maybeHistogramLabel: Option[String Refined NonEmpty] = None ): F[(ElapsedTime, A)] - def measureAndLogTime[A](condition: PartialFunction[A, String])( + def measureAndLogTime[A](message: PartialFunction[A, String])( block: F[A] )(implicit F: Monad[F], L: Logger[F]): F[A] = - measureExecutionTime(block).flatMap(logExecutionTimeWhen(condition)) + measureExecutionTime(block).flatMap(logExecutionTimeWhen(message)) def logExecutionTimeWhen[A]( - condition: PartialFunction[A, String] + message: PartialFunction[A, String] )(implicit F: Applicative[F], L: Logger[F]): ((ElapsedTime, A)) => F[A] = { resultAndTime => - logWarningIfAboveThreshold(resultAndTime, condition.lift).as(resultAndTime._2) + logWarningIfAboveThreshold(resultAndTime, message.lift).as(resultAndTime._2) } def logExecutionTime[A]( @@ -58,10 +58,10 @@ abstract class ExecutionTimeRecorder[F[_]](threshold: ElapsedTime) { private def logWarningIfAboveThreshold[A]( resultAndTime: (ElapsedTime, A), - condition: A => Option[String] + withMessage: A => Option[String] )(implicit F: Applicative[F], L: Logger[F]): F[Unit] = { val (elapsedTime, result) = resultAndTime - condition(result) + withMessage(result) .filter(_ => elapsedTime >= threshold) .map(message => L.warn(s"$message in ${elapsedTime}ms")) .getOrElse(F.unit) diff --git a/graph-commons/src/main/scala/io/renku/triplesstore/ProjectSparqlClient.scala b/graph-commons/src/main/scala/io/renku/triplesstore/ProjectSparqlClient.scala new file mode 100644 index 0000000000..6735a1b8b6 --- /dev/null +++ b/graph-commons/src/main/scala/io/renku/triplesstore/ProjectSparqlClient.scala @@ -0,0 +1,77 @@ +/* + * Copyright 2023 Swiss Data Science Center (SDSC) + * A partnership between École Polytechnique Fédérale de Lausanne (EPFL) and + * Eidgenössische Technische Hochschule Zürich (ETHZ). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.renku.triplesstore + +import cats.Monad +import cats.effect._ +import cats.syntax.all._ +import eu.timepit.refined.api.Refined +import eu.timepit.refined.collection.NonEmpty +import eu.timepit.refined.auto._ +import fs2.io.net.Network +import io.renku.jsonld.JsonLD +import io.renku.triplesstore.client.http.{Retry, SparqlClient, SparqlQuery, SparqlUpdate} +import org.typelevel.log4cats.Logger + +/** SparQL client fixed to the `projects` dataset. */ +trait ProjectSparqlClient[F[_]] extends SparqlClient[F] + +object ProjectSparqlClient { + def apply[F[_]: Monad: Logger: SparqlQueryTimeRecorder](c: SparqlClient[F]) = + new ProjectSparqlClient[F] { + private[this] val rec = SparqlQueryTimeRecorder[F].instance + override def update(request: SparqlUpdate) = { + val label = histogramLabel(request) + val work = c.update(request) + rec + .measureExecutionTime(work, label) + .flatMap(rec.logExecutionTime(s"Execute sparql update '$label'")) + } + + override def upload(data: JsonLD) = { + val label: String Refined NonEmpty = "jsonld upload" + val work = c.upload(data) + rec + .measureExecutionTime(work, label.some) + .flatMap(rec.logExecutionTime("Execute JSONLD upload")) + } + + override def query(request: SparqlQuery) = { + val label = histogramLabel(request) + val work = c.query(request) + rec + .measureExecutionTime(work, label) + .flatMap(rec.logExecutionTime(s"Execute sparql query '$label'")) + } + } + + def apply[F[_]: Network: Async: Logger: SparqlQueryTimeRecorder]( + cc: ProjectsConnectionConfig, + retryCfg: Retry.RetryConfig = Retry.RetryConfig.default + ): Resource[F, ProjectSparqlClient[F]] = { + val cfg = cc.toCC(Some(retryCfg)) + SparqlClient[F](cfg).map(apply(_)) + } + + private def histogramLabel(r: Any): Option[String Refined NonEmpty] = + r match { + case q: io.renku.triplesstore.SparqlQuery => q.name.some + case _ => None + } +} diff --git a/graph-commons/src/main/scala/io/renku/triplesstore/SparqlQuery.scala b/graph-commons/src/main/scala/io/renku/triplesstore/SparqlQuery.scala index a3d11027e5..3fbe115f17 100644 --- a/graph-commons/src/main/scala/io/renku/triplesstore/SparqlQuery.scala +++ b/graph-commons/src/main/scala/io/renku/triplesstore/SparqlQuery.scala @@ -27,17 +27,22 @@ import io.renku.jsonld.Schema import io.renku.tinytypes.StringTinyType import io.renku.triplesstore.SparqlQuery.Prefix import io.renku.triplesstore.client.sparql.Fragment +import io.renku.triplesstore.client.http.{SparqlQuery => ClientSparqlQuery, SparqlUpdate => ClientSparqlUpdate} final case class SparqlQuery(name: String Refined NonEmpty, prefixes: Set[Prefix], body: String, maybePagingRequest: Option[PagingRequest] -) { +) extends ClientSparqlQuery + with ClientSparqlUpdate { + override lazy val toString: String = s"""|${prefixes.mkString("", "\n", "")} |$body |$pagingRequest""".stripMargin.trim + override lazy val render: String = toString + private lazy val pagingRequest = maybePagingRequest .map { pagingRequest => diff --git a/graph-commons/src/main/scala/io/renku/triplesstore/SparqlQueryTimeRecorder.scala b/graph-commons/src/main/scala/io/renku/triplesstore/SparqlQueryTimeRecorder.scala index 67b9ef25c0..2963feec53 100644 --- a/graph-commons/src/main/scala/io/renku/triplesstore/SparqlQueryTimeRecorder.scala +++ b/graph-commons/src/main/scala/io/renku/triplesstore/SparqlQueryTimeRecorder.scala @@ -33,7 +33,7 @@ object SparqlQueryTimeRecorder { import io.renku.metrics.MetricsRegistry - def apply[F[_]: Sync: Logger: MetricsRegistry](): F[SparqlQueryTimeRecorder[F]] = MetricsRegistry[F] + def create[F[_]: Sync: Logger: MetricsRegistry](): F[SparqlQueryTimeRecorder[F]] = MetricsRegistry[F] .register { new LabeledHistogramImpl[F]( name = "sparql_execution_times", diff --git a/graph-commons/src/test/scala/io/renku/logging/TestSparqlQueryTimeRecorder.scala b/graph-commons/src/test/scala/io/renku/logging/TestSparqlQueryTimeRecorder.scala index b57b6836b5..b664441028 100644 --- a/graph-commons/src/test/scala/io/renku/logging/TestSparqlQueryTimeRecorder.scala +++ b/graph-commons/src/test/scala/io/renku/logging/TestSparqlQueryTimeRecorder.scala @@ -26,6 +26,6 @@ import org.typelevel.log4cats.Logger object TestSparqlQueryTimeRecorder { def apply[F[_]: Sync: Logger]: F[SparqlQueryTimeRecorder[F]] = { implicit val metricsRegistry: MetricsRegistry[F] = TestMetricsRegistry[F] - SparqlQueryTimeRecorder[F]() + SparqlQueryTimeRecorder.create[F]() } } diff --git a/graph-commons/src/test/scala/io/renku/triplesstore/ProjectSparqlClientSpec.scala b/graph-commons/src/test/scala/io/renku/triplesstore/ProjectSparqlClientSpec.scala new file mode 100644 index 0000000000..5ce8520a6d --- /dev/null +++ b/graph-commons/src/test/scala/io/renku/triplesstore/ProjectSparqlClientSpec.scala @@ -0,0 +1,124 @@ +/* + * Copyright 2023 Swiss Data Science Center (SDSC) + * A partnership between École Polytechnique Fédérale de Lausanne (EPFL) and + * Eidgenössische Technische Hochschule Zürich (ETHZ). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.renku.triplesstore + +import cats.effect.IO +import cats.effect.testing.scalatest.AsyncIOSpec +import eu.timepit.refined.auto._ +import io.prometheus.client.Histogram +import io.renku.cli.model.CliSoftwareAgent +import io.renku.graph.model.agents +import io.renku.interpreters.TestLogger +import io.renku.jsonld.syntax._ +import io.renku.logging.TestExecutionTimeRecorder +import io.renku.triplesstore.client.syntax._ +import io.renku.triplesstore.client.util.JenaContainerSupport +import org.scalatest.flatspec.AsyncFlatSpec +import org.scalatest.matchers.should +import org.typelevel.log4cats.Logger + +class ProjectSparqlClientSpec extends AsyncFlatSpec with AsyncIOSpec with JenaContainerSupport with should.Matchers { + implicit val logger: Logger[IO] = TestLogger() + + val makeHistogram = IO( + new Histogram.Builder().name("test").help("test").labelNames("update").buckets(0.5, 0.8).create() + ) + + def makeSparqlQueryTimeRecorder(h: Histogram): SparqlQueryTimeRecorder[IO] = + new SparqlQueryTimeRecorder[IO](TestExecutionTimeRecorder[IO](Some(h))) + + def withProjectClient(implicit sqr: SparqlQueryTimeRecorder[IO]) = + withDataset("projects").map(ProjectSparqlClient.apply(_)) + + def assertSampled(histogram: Histogram) = + histogram.collect().get(0).samples.size should be > 0 + + def assertNotSampled(histogram: Histogram) = + histogram.collect().get(0).samples.size shouldBe 0 + + def resetHistogram(histogram: Histogram) = { + histogram.clear() + assertNotSampled(histogram) + } + + it should "measure execution time for named queries" in { + val histogram = makeHistogram.unsafeRunSync() + implicit val sr: SparqlQueryTimeRecorder[IO] = makeSparqlQueryTimeRecorder(histogram) + withProjectClient.use { c => + for { + _ <- IO(assertNotSampled(histogram)) + up = SparqlQuery.apply( + name = "test-update", + prefixes = Set.empty, + body = sparql""" + |PREFIX p: + |INSERT DATA { + | p:fred p:hasSpouse p:wilma . + | p:fred p:hasChild p:pebbles . + | p:wilma p:hasChild p:pebbles . + | p:pebbles p:hasSpouse p:bamm-bamm ; + | p:hasChild p:roxy, p:chip. + |}""".stripMargin + ) + _ <- c.update(up) + _ = assertSampled(histogram) + + _ <- IO(resetHistogram(histogram)) + q = SparqlQuery( + name = "test-query", + prefixes = Set.empty, + body = sparql"SELECT * WHERE { ?s ?p ?o } LIMIT 1" + ) + _ <- c.query(q) + _ = assertSampled(histogram) + + _ <- IO(resetHistogram(histogram)) + data = CliSoftwareAgent(agents.ResourceId("http://u.rl"), agents.Name("test")).asJsonLD + _ <- c.upload(data) + _ = assertSampled(histogram) + } yield () + } + } + + it should "not measure execution time for un-named queries" in { + val histogram = makeHistogram.unsafeRunSync() + implicit val sr: SparqlQueryTimeRecorder[IO] = makeSparqlQueryTimeRecorder(histogram) + + withProjectClient.use { c => + for { + _ <- IO(assertNotSampled(histogram)) + + q = sparql""" + |PREFIX p: + |INSERT DATA { + | p:fred p:hasSpouse p:wilma . + | p:fred p:hasChild p:pebbles . + | p:wilma p:hasChild p:pebbles . + | p:pebbles p:hasSpouse p:bamm-bamm ; + | p:hasChild p:roxy, p:chip. + |}""".stripMargin + + _ <- c.update(q) + + _ = assertNotSampled(histogram) + } yield () + } + } + +} diff --git a/knowledge-graph/src/main/scala/io/renku/knowledgegraph/Microservice.scala b/knowledge-graph/src/main/scala/io/renku/knowledgegraph/Microservice.scala index 0cf8fa6ba1..69fe42d23a 100644 --- a/knowledge-graph/src/main/scala/io/renku/knowledgegraph/Microservice.scala +++ b/knowledge-graph/src/main/scala/io/renku/knowledgegraph/Microservice.scala @@ -38,7 +38,7 @@ object Microservice extends IOMicroservice { override def run(args: List[String]): IO[ExitCode] = for { implicit0(mr: MetricsRegistry[IO]) <- MetricsRegistry[IO]() - implicit0(sqtr: SparqlQueryTimeRecorder[IO]) <- SparqlQueryTimeRecorder[IO]() + implicit0(sqtr: SparqlQueryTimeRecorder[IO]) <- SparqlQueryTimeRecorder.create[IO]() projectConnConfig <- ProjectsConnectionConfig[IO]() certificateLoader <- CertificateLoader[IO] sentryInitializer <- SentryInitializer[IO] diff --git a/project-auth/src/test/scala/io/renku/projectauth/ProjectAuthServiceSpec.scala b/project-auth/src/test/scala/io/renku/projectauth/ProjectAuthServiceSpec.scala index b4abc443b5..f402ff03f6 100644 --- a/project-auth/src/test/scala/io/renku/projectauth/ProjectAuthServiceSpec.scala +++ b/project-auth/src/test/scala/io/renku/projectauth/ProjectAuthServiceSpec.scala @@ -27,13 +27,13 @@ import io.renku.generators.Generators.Implicits._ import io.renku.graph.model.RenkuUrl import io.renku.graph.model.persons.GitLabId import io.renku.graph.model.projects.{Role, Visibility} -import io.renku.triplesstore.client.util.JenaContainerSpec +import io.renku.triplesstore.client.util.JenaContainerSupport import org.scalatest.flatspec.AsyncFlatSpec import org.scalatest.matchers.should import org.typelevel.log4cats.Logger import org.typelevel.log4cats.slf4j.Slf4jLogger -class ProjectAuthServiceSpec extends AsyncFlatSpec with AsyncIOSpec with JenaContainerSpec with should.Matchers { +class ProjectAuthServiceSpec extends AsyncFlatSpec with AsyncIOSpec with JenaContainerSupport with should.Matchers { implicit val logger: Logger[IO] = Slf4jLogger.getLogger[IO] implicit val renkuUrl: RenkuUrl = RenkuUrl("http://localhost/renku") diff --git a/triples-generator/src/main/scala/io/renku/triplesgenerator/Microservice.scala b/triples-generator/src/main/scala/io/renku/triplesgenerator/Microservice.scala index 83b9fd12fa..828bc4354b 100644 --- a/triples-generator/src/main/scala/io/renku/triplesgenerator/Microservice.scala +++ b/triples-generator/src/main/scala/io/renku/triplesgenerator/Microservice.scala @@ -42,7 +42,7 @@ import io.renku.triplesgenerator.events.consumers.tsmigrationrequest.migrations. import io.renku.triplesgenerator.events.consumers.tsprovisioning.{minprojectinfo, triplesgenerated} import io.renku.triplesgenerator.init.{CliVersionCompatibilityChecker, CliVersionCompatibilityVerifier} import io.renku.triplesgenerator.metrics.MetricsService -import io.renku.triplesstore.{ProjectsConnectionConfig, SparqlQueryTimeRecorder} +import io.renku.triplesstore.{ProjectSparqlClient, ProjectsConnectionConfig, SparqlQueryTimeRecorder} import natchez.Trace.Implicits.noop import org.http4s.server.Server import org.typelevel.log4cats.Logger @@ -68,12 +68,15 @@ object Microservice extends IOMicroservice { dbSessionPool <- Resource .eval(new TgLockDbConfigProvider[IO].map(SessionPoolResource[IO, TgLockDB])) .flatMap(identity) + implicit0(mr: MetricsRegistry[IO]) <- Resource.eval(MetricsRegistry[IO]()) + implicit0(sqtr: SparqlQueryTimeRecorder[IO]) <- Resource.eval(SparqlQueryTimeRecorder.create[IO]()) + projectConnConfig <- Resource.eval(ProjectsConnectionConfig[IO](config)) projectsSparql <- ProjectSparqlClient[IO](projectConnConfig) - } yield (config, dbSessionPool, projectsSparql) + } yield (config, dbSessionPool, projectsSparql, mr, sqtr) - resources.use { case (config, dbSessionPool, projectSparqlClient) => - doRun(config, dbSessionPool, projectSparqlClient) + resources.use { case (config, dbSessionPool, projectSparqlClient, mr, sqtr) => + doRun(config, dbSessionPool, projectSparqlClient)(mr, sqtr) } } @@ -81,12 +84,11 @@ object Microservice extends IOMicroservice { config: Config, dbSessionPool: SessionResource[IO, TgLockDB], projectSparqlClient: ProjectSparqlClient[IO] - ): IO[ExitCode] = for { - implicit0(mr: MetricsRegistry[IO]) <- MetricsRegistry[IO]() - implicit0(sqtr: SparqlQueryTimeRecorder[IO]) <- SparqlQueryTimeRecorder[IO]() - implicit0(gc: GitLabClient[IO]) <- GitLabClient[IO]() - implicit0(acf: AccessTokenFinder[IO]) <- AccessTokenFinder[IO]() - implicit0(rp: ReProvisioningStatus[IO]) <- ReProvisioningStatus[IO]() + )(implicit mr: MetricsRegistry[IO], sqtr: SparqlQueryTimeRecorder[IO]): IO[ExitCode] = for { + + implicit0(gc: GitLabClient[IO]) <- GitLabClient[IO]() + implicit0(acf: AccessTokenFinder[IO]) <- AccessTokenFinder[IO]() + implicit0(rp: ReProvisioningStatus[IO]) <- ReProvisioningStatus[IO]() _ <- TgLockDB.migrate[IO](dbSessionPool, 20.seconds) diff --git a/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/ProjectAuthSync.scala b/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/ProjectAuthSync.scala index 48998d4cec..03033ddc93 100644 --- a/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/ProjectAuthSync.scala +++ b/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/ProjectAuthSync.scala @@ -25,7 +25,7 @@ import fs2.io.net.Network import io.renku.graph.model.RenkuUrl import io.renku.graph.model.projects.{Slug, Visibility} import io.renku.projectauth.{ProjectAuthData, ProjectAuthService, ProjectMember} -import io.renku.triplesstore.ProjectsConnectionConfig +import io.renku.triplesstore.{ProjectSparqlClient, ProjectsConnectionConfig, SparqlQueryTimeRecorder} import io.renku.triplesstore.client.http.{RowDecoder, SparqlClient} import io.renku.triplesstore.client.syntax._ import org.typelevel.log4cats.Logger @@ -37,7 +37,9 @@ trait ProjectAuthSync[F[_]] { object ProjectAuthSync { - def resource[F[_]: Async: Logger: Network](cc: ProjectsConnectionConfig)(implicit renkuUrl: RenkuUrl) = + def resource[F[_]: Async: Logger: Network: SparqlQueryTimeRecorder](cc: ProjectsConnectionConfig)(implicit + renkuUrl: RenkuUrl + ) = ProjectSparqlClient[F](cc).map(apply[F]) def apply[F[_]: Sync]( diff --git a/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/ProjectSparqlClient.scala b/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/ProjectSparqlClient.scala deleted file mode 100644 index 819ac0be51..0000000000 --- a/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/ProjectSparqlClient.scala +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2023 Swiss Data Science Center (SDSC) - * A partnership between École Polytechnique Fédérale de Lausanne (EPFL) and - * Eidgenössische Technische Hochschule Zürich (ETHZ). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.renku.triplesgenerator.events.consumers - -import cats.effect._ -import fs2.io.net.Network -import io.renku.jsonld.JsonLD -import io.renku.triplesstore.ProjectsConnectionConfig -import io.renku.triplesstore.client.http.{Retry, SparqlClient, SparqlQuery, SparqlUpdate} -import org.typelevel.log4cats.Logger - -/** SparQL client fixed to the `projects` dataset. */ -trait ProjectSparqlClient[F[_]] extends SparqlClient[F] - -object ProjectSparqlClient { - def apply[F[_]: Network: Async: Logger]( - cc: ProjectsConnectionConfig, - retryCfg: Retry.RetryConfig = Retry.RetryConfig.default - ): Resource[F, ProjectSparqlClient[F]] = { - val cfg = cc.toCC(Some(retryCfg)) - SparqlClient[F](cfg).map(c => - new ProjectSparqlClient[F] { - override def update(request: SparqlUpdate) = c.update(request) - override def upload(data: JsonLD) = c.upload(data) - override def query(request: SparqlQuery) = c.query(request) - } - ) - } -} diff --git a/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/EventHandler.scala b/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/EventHandler.scala index 96611a3068..a3385f270b 100644 --- a/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/EventHandler.scala +++ b/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/EventHandler.scala @@ -31,7 +31,7 @@ import io.renku.lock.syntax._ import io.renku.http.client.GitLabClient import io.renku.lock.Lock import io.renku.triplesgenerator.TgLockDB.TsWriteLock -import io.renku.triplesstore.SparqlQueryTimeRecorder +import io.renku.triplesstore.{ProjectSparqlClient, SparqlQueryTimeRecorder} import org.typelevel.log4cats.Logger import tsmigrationrequest.migrations.reprovisioning.ReProvisioningStatus diff --git a/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/MembersSynchronizer.scala b/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/MembersSynchronizer.scala index f7f874d309..fb40fc0cb2 100644 --- a/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/MembersSynchronizer.scala +++ b/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/MembersSynchronizer.scala @@ -26,7 +26,6 @@ import io.renku.graph.tokenrepository.AccessTokenFinder import io.renku.http.client.{AccessToken, GitLabClient} import io.renku.logging.ExecutionTimeRecorder import io.renku.logging.ExecutionTimeRecorder.ElapsedTime -import io.renku.triplesgenerator.events.consumers.ProjectSparqlClient import io.renku.triplesgenerator.gitlab.GitLabProjectMembersFinder import io.renku.triplesstore._ import org.typelevel.log4cats.Logger diff --git a/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/SubscriptionFactory.scala b/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/SubscriptionFactory.scala index f2984585ed..fbe686b2b0 100644 --- a/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/SubscriptionFactory.scala +++ b/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/SubscriptionFactory.scala @@ -28,7 +28,7 @@ import io.renku.graph.tokenrepository.AccessTokenFinder import io.renku.http.client.GitLabClient import io.renku.triplesgenerator.Microservice import io.renku.triplesgenerator.TgLockDB.TsWriteLock -import io.renku.triplesgenerator.events.consumers.ProjectSparqlClient +import io.renku.triplesstore.ProjectSparqlClient import io.renku.triplesgenerator.events.consumers.tsmigrationrequest.migrations.reprovisioning.ReProvisioningStatus import io.renku.triplesstore.SparqlQueryTimeRecorder import org.typelevel.log4cats.Logger diff --git a/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/namedgraphs/KGSynchronizer.scala b/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/namedgraphs/KGSynchronizer.scala index 66c20ecc04..a777212104 100644 --- a/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/namedgraphs/KGSynchronizer.scala +++ b/triples-generator/src/main/scala/io/renku/triplesgenerator/events/consumers/membersync/namedgraphs/KGSynchronizer.scala @@ -24,7 +24,7 @@ import cats.effect._ import cats.syntax.all._ import io.renku.graph.config.RenkuUrlLoader import io.renku.graph.model.{RenkuUrl, projects} -import io.renku.triplesgenerator.events.consumers.{ProjectAuthSync, ProjectSparqlClient} +import io.renku.triplesgenerator.events.consumers.ProjectAuthSync import io.renku.triplesgenerator.gitlab.GitLabProjectMember import io.renku.triplesstore._ import org.typelevel.log4cats.Logger diff --git a/triples-generator/src/test/scala/io/renku/triplesgenerator/DatasetProvision.scala b/triples-generator/src/test/scala/io/renku/triplesgenerator/DatasetProvision.scala index 71ca86691d..cda78a9101 100644 --- a/triples-generator/src/test/scala/io/renku/triplesgenerator/DatasetProvision.scala +++ b/triples-generator/src/test/scala/io/renku/triplesgenerator/DatasetProvision.scala @@ -23,9 +23,10 @@ import io.renku.entities.searchgraphs.SearchInfoDatasets import io.renku.graph.model.entities.EntityFunctions import io.renku.graph.model.projects.Role import io.renku.graph.model.{RenkuUrl, entities} +import io.renku.logging.{ExecutionTimeRecorder, TestExecutionTimeRecorder} import io.renku.projectauth.ProjectMember -import io.renku.triplesgenerator.events.consumers.{ProjectAuthSync, ProjectSparqlClient} -import io.renku.triplesstore.{GraphsProducer, InMemoryJena, ProjectsDataset} +import io.renku.triplesgenerator.events.consumers.ProjectAuthSync +import io.renku.triplesstore._ trait DatasetProvision extends SearchInfoDatasets { self: ProjectsDataset with InMemoryJena => @@ -36,6 +37,9 @@ trait DatasetProvision extends SearchInfoDatasets { self: ProjectsDataset with I graphsProducer: GraphsProducer[entities.Project], renkuUrl: RenkuUrl ): IO[Unit] = { + val execTimeRecorder: ExecutionTimeRecorder[IO] = TestExecutionTimeRecorder[IO]() + implicit val sparqlQueryTimeRecorder: SparqlQueryTimeRecorder[IO] = + new SparqlQueryTimeRecorder[IO](execTimeRecorder) val ps = ProjectSparqlClient[IO](projectsDSConnectionInfo).map(ProjectAuthSync[IO](_)) val members = project.members.flatMap(p => p.maybeGitLabId.map(id => ProjectMember(id, Role.Reader))) super.provisionProject(project) *> ps.use(_.syncProject(project.slug, members)) diff --git a/triples-store-client/src/main/scala/io/renku/triplesstore/client/http/SparqlClient.scala b/triples-store-client/src/main/scala/io/renku/triplesstore/client/http/SparqlClient.scala index cba2baa6ac..6bb0c20294 100644 --- a/triples-store-client/src/main/scala/io/renku/triplesstore/client/http/SparqlClient.scala +++ b/triples-store-client/src/main/scala/io/renku/triplesstore/client/http/SparqlClient.scala @@ -39,7 +39,7 @@ trait SparqlClient[F[_]] { /** The sparql query operation, returning results as JSON. */ def query(request: SparqlQuery): F[Json] - def queryDecode[A](request: SparqlQuery)(implicit d: RowDecoder[A], F: MonadThrow[F]): F[List[A]] = { + final def queryDecode[A](request: SparqlQuery)(implicit d: RowDecoder[A], F: MonadThrow[F]): F[List[A]] = { val decoder = Decoder .instance(c => c.downField("results").downField("bindings").as[List[A]]) .withErrorMessage(s"Decoding Sparql result failed for request: $request") diff --git a/triples-store-client/src/test/scala/io/renku/triplesstore/client/http/SparqlClientSpec.scala b/triples-store-client/src/test/scala/io/renku/triplesstore/client/http/SparqlClientSpec.scala index 0776d15e45..fef34d599a 100644 --- a/triples-store-client/src/test/scala/io/renku/triplesstore/client/http/SparqlClientSpec.scala +++ b/triples-store-client/src/test/scala/io/renku/triplesstore/client/http/SparqlClientSpec.scala @@ -27,11 +27,11 @@ import org.scalatest.matchers.should import org.typelevel.log4cats.Logger import org.typelevel.log4cats.slf4j.Slf4jLogger import io.renku.triplesstore.client.syntax._ -import io.renku.triplesstore.client.util.JenaContainerSpec +import io.renku.triplesstore.client.util.JenaContainerSupport import java.time.Instant -class SparqlClientSpec extends AsyncFlatSpec with AsyncIOSpec with JenaContainerSpec with should.Matchers { +class SparqlClientSpec extends AsyncFlatSpec with AsyncIOSpec with JenaContainerSupport with should.Matchers { implicit val logger: Logger[IO] = Slf4jLogger.getLogger[IO] val dataset = "projects" diff --git a/triples-store-client/src/test/scala/io/renku/triplesstore/client/util/JenaContainerDirectSpec.scala b/triples-store-client/src/test/scala/io/renku/triplesstore/client/util/JenaContainerDirectSupport.scala similarity index 94% rename from triples-store-client/src/test/scala/io/renku/triplesstore/client/util/JenaContainerDirectSpec.scala rename to triples-store-client/src/test/scala/io/renku/triplesstore/client/util/JenaContainerDirectSupport.scala index 5a7fb370c4..56bb5d7e01 100644 --- a/triples-store-client/src/test/scala/io/renku/triplesstore/client/util/JenaContainerDirectSpec.scala +++ b/triples-store-client/src/test/scala/io/renku/triplesstore/client/util/JenaContainerDirectSupport.scala @@ -25,7 +25,7 @@ import org.scalatest.{BeforeAndAfterAll, Suite} import org.typelevel.log4cats.Logger /** Trait for having a client directly accessible using "unsafe" effects. */ -trait JenaContainerDirectSpec extends JenaContainerSpec with BeforeAndAfterAll { self: Suite => +trait JenaContainerDirectSupport extends JenaContainerSupport with BeforeAndAfterAll { self: Suite => implicit def logger: Logger[IO] implicit val ioRuntime: IORuntime diff --git a/triples-store-client/src/test/scala/io/renku/triplesstore/client/util/JenaContainerSpec.scala b/triples-store-client/src/test/scala/io/renku/triplesstore/client/util/JenaContainerSupport.scala similarity index 96% rename from triples-store-client/src/test/scala/io/renku/triplesstore/client/util/JenaContainerSpec.scala rename to triples-store-client/src/test/scala/io/renku/triplesstore/client/util/JenaContainerSupport.scala index 2fd529915b..5ef2338399 100644 --- a/triples-store-client/src/test/scala/io/renku/triplesstore/client/util/JenaContainerSpec.scala +++ b/triples-store-client/src/test/scala/io/renku/triplesstore/client/util/JenaContainerSupport.scala @@ -29,7 +29,7 @@ import org.typelevel.log4cats.Logger import scala.concurrent.duration._ -trait JenaContainerSpec extends ForAllTestContainer { self: Suite => +trait JenaContainerSupport extends ForAllTestContainer { self: Suite => protected val runMode: JenaRunMode = JenaRunMode.GenericContainer protected val timeout: Duration = 2.minutes