Skip to content

Instantly share code, notes, and snippets.

@samspills
Created January 19, 2023 23:09
Show Gist options
  • Select an option

  • Save samspills/bc19761752107f072d6ca608c8067d2b to your computer and use it in GitHub Desktop.

Select an option

Save samspills/bc19761752107f072d6ca608c8067d2b to your computer and use it in GitHub Desktop.
toy example of an http server to query or update a ref inside of a class, which is also being updated on a schedule
//> using lib "co.fs2::fs2-core:3.5.0"
//> using lib "org.typelevel::cats-effect:3.4.5"
//
//> using lib "org.http4s::http4s-core:0.23.18"
//> using lib "org.http4s::http4s-dsl:0.23.18"
//> using lib "org.http4s::http4s-ember-server:0.23.18"
//> using lib "org.http4s::http4s-server:0.23.18"
import fs2.Stream
import cats.effect.IO
import cats.effect.IOApp
import scala.concurrent.duration._
import cats.effect.kernel.Ref
import org.http4s.HttpRoutes
import org.http4s.dsl.io._
import org.http4s.implicits._
import org.http4s.server.Router
import org.http4s.ember.server.EmberServerBuilder
import com.comcast.ip4s._
import cats.effect.ExitCode
import cats.effect.kernel.Resource
import org.http4s.server.Server
class InMemoryThing(private val value: Ref[IO, Int]) {
def get: IO[Int] = value.get
def set(i: Int): IO[Unit] = value.set(i)
def updateAndGet(f: Int => Int): IO[Int] = value.updateAndGet(f)
}
object ScheduledEndpoint extends IOApp {
def refService(thing: InMemoryThing) = HttpRoutes.of[IO] {
case GET -> Root / "ref" =>
for {
i <- thing.get
resp <- Ok(s"Current ref value is: $i")
} yield resp
case PUT -> Root / "ref" / IntVar(value) =>
for {
_ <- thing.set(value)
resp <- Ok(s"Updated the ref value to: $value")
} yield resp
}
def scheduledUpdater(thing: InMemoryThing): Resource[IO, Unit] = {
val prog = thing
.updateAndGet(i => i + 1)
.flatMap(i => IO.println(s"scheduled update: added 1, ref value is now $i"))
Stream.repeatEval(prog).metered(30.seconds).compile.resource.drain
}
def run(args: List[String]): IO[ExitCode] = {
val serverAndUpdater: Resource[IO, (Server, Unit)] = for {
thing <- Resource.eval(Ref[IO].of(1)).map(InMemoryThing(_))
httpApp = Router("/" -> refService(thing)).orNotFound
server = EmberServerBuilder
.default[IO]
.withHost(ipv4"0.0.0.0")
.withPort(port"8080")
.withHttpApp(httpApp)
.build
updater = scheduledUpdater(thing)
serverAndUpdater <- Resource.both(server, updater)
} yield serverAndUpdater
serverAndUpdater.useForever.as(ExitCode.Success)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment