A small Scala akka library for locking critical sections of code using a binary semaphore without blocking. The use case is primarily for interacting with external sources (i.e. preventing parallel requests to an external service). You should not need to lock on code which stays inside your application (Use a single actor instead).
Simple example:
val lock1 = "LOCK" // the lockObj can be of any type
val action1 = () ⇒ { someCode() } // your code is executed in a future
val action2 = () ⇒ { someOtherCode() } // the lock is released when your code returns
val lock2 = 1337
val action3 = () ⇒ { someReallyOtherCode() }
lockActor ! LockAwareMessage(lock1, action1) // messages run in the order they are received
lockActor ! LockAwareMessage(lock1, action2) // does not run in parallel with action1
lockActor ! LockAwareMessage(lock2, action3) // runs in parallel to action1 & action2
Add this to your build.sbt
for Scala 2.12 & 2.11 (last version for Scala 2.10 is 0.0.3
):
resolvers += "bleibinha.us/archiva releases" at "http://bleibinha.us/archiva/repository/releases"
libraryDependencies ++= Seq(
"us.bleibinha" %% "akka-actor-locking" % "0.0.7"
)
Get the lockActor:
import akka.actor.ActorSystem
import us.bleibinha.akka.actor.locking._ // imports everything needed
implicit val actorSystem = ActorSystem() // is an implicit argument to the LockActor
val lockActor = LockActor()
- Support for action code with a Future return type. The lock will be active until the returned Future completes. Warning: Make sure the returned Future 'waits' on all others if you are using multiple Futures in the action block. Future.sequence might come in handy.
val action = () ⇒ {
someCode()
Future { someMoreCode() }
}
lockActor ! LockAwareMessage(lockObj, action)
LockAwareRequest
sends back the result to the requesting actor. This is practical in combination with the ask pattern. If you are already inside an actor, you can also use aLockAwareMessage
andself ! Something
to reply.
val request = () ⇒ "Hello"
val result = lockActor.ask(LockAwareRequest(lockObj, request))
result map println // prints "Hello"
- All action code is executed in a wrapping
Future
not blocking the lockActor from other requests. - The code is non-blocking.
- Manually release a lock. Warning: This will not cancel running processes using that lock.
lockActor ! Unlock(lockObj)
- Order of incoming messages to the lockActor is maintained.
- The lock is released when the action code throws an exception.
- Built with Scala 2.12.4 & Scala 2.11.12 and akka 2.5.8.
- Tested.