keysemaphore - Keyed Semaphores 
Quick Start
To use keysemaphore in an existing SBT project with Scala 2.12, 2.13, or 3.0, add the following dependencies to your
build.sbt
depending on your needs:
libraryDependencies ++= Seq(
"io.chrisdavenport" %% "keysemaphore" % "<version>"
)
Example
Quick Imports
import cats.effect._
import io.chrisdavenport.keysemaphore.KeySemaphore
import cats.effect.unsafe.implicits.global
Then we build some operations
// Second Action Can't Get Permit
val action1 = {
for {
sem <- KeySemaphore.of[IO, Unit]{_ => 1L}
first <- sem(()).tryAcquire
second <- sem(()).tryAcquire
} yield (first, second)
}
// action1: IO[Tuple2[Boolean, Boolean]] = FlatMap(
// Map(
// Delay(
// cats.effect.IO$$$Lambda$15019/400788471@421581aa,
// cats.effect.tracing.TracingEvent$StackTrace
// ),
// io.chrisdavenport.keysemaphore.KeySemaphore$$$Lambda$15020/1590923540@626fec8,
// cats.effect.tracing.TracingEvent$StackTrace
// ),
// repl.MdocSession$App$$Lambda$15021/817388651@19a6cf92,
// cats.effect.tracing.TracingEvent$StackTrace
// )
action1.unsafeRunSync()
// res0: Tuple2[Boolean, Boolean] = (true, false)
// Not Affected By Other Keys
val action2 = {
for {
sem <- KeySemaphore.of[IO, Int]{(_: Int) => 1L}
first <- sem(1).tryAcquire
second <- sem(2).tryAcquire
third <- sem(1).tryAcquire
} yield (first, second, third)
}
// action2: IO[Tuple3[Boolean, Boolean, Boolean]] = FlatMap(
// Map(
// Delay(
// cats.effect.IO$$$Lambda$15019/400788471@36e4d7a1,
// cats.effect.tracing.TracingEvent$StackTrace
// ),
// io.chrisdavenport.keysemaphore.KeySemaphore$$$Lambda$15020/1590923540@6fcfc390,
// cats.effect.tracing.TracingEvent$StackTrace
// ),
// repl.MdocSession$App$$Lambda$15061/1151402737@5f5ca80f,
// cats.effect.tracing.TracingEvent$StackTrace
// )
action2.unsafeRunSync()
// res1: Tuple3[Boolean, Boolean, Boolean] = (true, true, false)
// Releases Based on Keys
// This is space safe, so when the semaphore returns to the
// default it removes it from the internal so memory is not
// leaked per key
val action3 = {
for {
sem <- KeySemaphore.of[IO, Int]{(_: Int) => 1L}
first <- sem(1).tryAcquire
second <- sem(1).tryAcquire
_ <- sem(1).release
third <- sem(1).tryAcquire
} yield (first, second, third)
}
// action3: IO[Tuple3[Boolean, Boolean, Boolean]] = FlatMap(
// Map(
// Delay(
// cats.effect.IO$$$Lambda$15019/400788471@492e1088,
// cats.effect.tracing.TracingEvent$StackTrace
// ),
// io.chrisdavenport.keysemaphore.KeySemaphore$$$Lambda$15020/1590923540@59e78fd3,
// cats.effect.tracing.TracingEvent$StackTrace
// ),
// repl.MdocSession$App$$Lambda$15066/1050643416@48a5143c,
// cats.effect.tracing.TracingEvent$StackTrace
// )
action3.unsafeRunSync()
// res2: Tuple3[Boolean, Boolean, Boolean] = (true, false, true)