diff --git a/src/main/scala/Server.scala b/src/main/scala/Server.scala index 82996ea..0742203 100644 --- a/src/main/scala/Server.scala +++ b/src/main/scala/Server.scala @@ -1,26 +1,29 @@ import cats.effect._ +import cats.effect.std.Semaphore import configuration.{Configuration, ConfigurationUtils, SystemPropertyReader} +import org.http4s.ember.client.EmberClientBuilder import utils.HttpClient object Server extends IOApp { def run(args: List[String]): IO[ExitCode] = { - val configReader = SystemPropertyReader - val httpClient = new HttpClient() - val configIO: IO[Configuration] = ConfigurationUtils.create(configReader, httpClient) - val memoizedConfigIO: IO[IO[Configuration]] = configIO.memoize - - def periodicTask(configIO: IO[Configuration]): IO[Unit] = - for { - config <- configIO - _ <- WatchlistSync.run(config, httpClient) - _ <- IO.sleep(config.refreshInterval) - _ <- periodicTask(configIO) - } yield () + val maxConcurrentOutgoingRequests = 1 for { - getConfig <- memoizedConfigIO - result <- periodicTask(getConfig).foreverM.as(ExitCode.Success) + semaphore <- Semaphore[IO](maxConcurrentOutgoingRequests) + configReader = SystemPropertyReader + clientResource = EmberClientBuilder.default[IO].build + httpClient = new HttpClient(clientResource, semaphore) + memoizedConfigIo <- ConfigurationUtils.create(configReader, httpClient).memoize + result <- periodicTask(memoizedConfigIo, httpClient).foreverM.as(ExitCode.Success) } yield result } + + private def periodicTask(configIO: IO[Configuration], httpClient: HttpClient): IO[Unit] = + for { + config <- configIO + _ <- WatchlistSync.run(config, httpClient) + _ <- IO.sleep(config.refreshInterval) + _ <- periodicTask(configIO, httpClient) + } yield () } diff --git a/src/main/scala/utils/HttpClient.scala b/src/main/scala/utils/HttpClient.scala index a4e79c5..b8e4f5e 100644 --- a/src/main/scala/utils/HttpClient.scala +++ b/src/main/scala/utils/HttpClient.scala @@ -1,26 +1,26 @@ package utils -import cats.effect.IO +import cats.effect.{IO, Resource} import io.circe.Json import org.http4s.{Header, Method, Request, Uri} -import org.http4s.ember.client.EmberClientBuilder import org.typelevel.ci.CIString import org.http4s.circe._ +import org.http4s.client.Client import org.slf4j.LoggerFactory +import cats.effect.std.Semaphore -class HttpClient { +class HttpClient(http4sClient: Resource[IO, Client[IO]], semaphore: Semaphore[IO]) { private val logger = LoggerFactory.getLogger(getClass) - private val clientResource = EmberClientBuilder - .default[IO] - .build - def httpRequest(method: Method, url: Uri, apiKey: Option[String] = None, payload: Option[Json] = None): IO[Either[Throwable, Json]] = { val baseRequest = Request[IO](method = method, uri = url).withHeaders(Header.Raw(CIString("Accept"), "application/json")) val requestWithApiKey = apiKey.fold(baseRequest)(key => baseRequest.withHeaders(Header.Raw(CIString("X-Api-Key"), key))) val requestWithPayload = payload.fold(requestWithApiKey)(p => requestWithApiKey.withEntity(p)) logger.info(s"Thread: ${Thread.currentThread()}") - clientResource.use(_.expect[Json](requestWithPayload).attempt) + + semaphore.permit.use { _ => + http4sClient.use(_.expect[Json](requestWithPayload).attempt) + } } -} +} \ No newline at end of file