Skip to content

TimWSpence/cats-stm

Repository files navigation

Cats STM

Build Status Latest version Discord Scala Steward badge

Composable in-memory transactions for Cats Effect which will handle locking, optimistic concurrency and automatic retries for you. The STM runtime takes care of acquiring locks in the correct order so your transactions are safe and should not deadlock. This locking is optimistic so it will only acquire the minimal set of locks and only when necessary to commit the result of a transaction.

For more information, see the microsite.

Example

import scala.concurrent.duration._

import cats.effect.{IO, IOApp}

import io.github.timwspence.cats.stm.__

object Main extends IOApp.Simple {

  override def run: IO[Unit] = STM.runtime[IO].flatMap(run(_))

  def run(stm: STM[IO]): IO[Unit] = {
    import stm._

    def transfer(accountForTim: TVar[Long], accountForSteve: TVar[Long]): IO[Unit] =
      stm.commit {
        for {
          balance <- accountForTim.get
          _       <- stm.check(balance > 100)
          _       <- accountForTim.modify(_ - 100)
          _       <- accountForSteve.modify(_ + 100)
        } yield ()
      }

    def giveTimMoreMoney(accountForTim: TVar[Long]): IO[Unit] =
      for {
        _ <- IO.sleep(5000.millis)
        _ <- stm.commit(accountForTim.modify(_ + 1))
      } yield ()

    def printBalances(accountForTim: TVar[Long], accountForSteve: TVar[Long]): IO[Unit] =
      for {
        t <- stm.commit(for {
          t <- accountForTim.get
          s <- accountForSteve.get
        } yield (t, s))
        (amountForTim, amountForSteve) = t
        _ <- IO(println(s"Tim: $amountForTim"))
        _ <- IO(println(s"Steve: $amountForSteve"))
      } yield ()

    for {
      accountForTim   <- stm.commit(TVar.of[Long](100))
      accountForSteve <- stm.commit(TVar.of[Long](0))
      _               <- printBalances(accountForTim, accountForSteve)
      _               <- giveTimMoreMoney(accountForTim).start
      _               <- transfer(accountForTim, accountForSteve)
      _               <- printBalances(accountForTim, accountForSteve)
    } yield ()

  }

}

Documentation

The documentation is built using docusaurus. You can generate it via nix-shell --run "sbt docs/docusaurusCreateSite" . You can then view it via nix-shell --run "cd website && npm start".

Credits

This software was inspired by Beautiful Concurrency and the stm package.

Many thanks to @impurepics for the awesome logo!

Tool Sponsorship

Development of Cats STM is generously supported in part by YourKit through the use of their excellent Java profiler.