Distributed lock library in scala. based on mongodb (using reactivemongo or mongo-scala-driver)
consists of 3 modules:
- scalalock-api - contains the api and the locking logic
- scalalock-mongo - an api implementation using mongodb as the lock persistence store. implementation is dependant on mongo-scala-driver.
- scalalock-reactivemongo - an alternative api implementation using reactivemongo as the mongodb driver. implementation is dependant on reactivemongo.
- Add dependencies to
build.sbt
:
- Option A - if you're using mongo-scala-driver
libraryDependencies ++= Seq( "com.weirddev" %% "scalalock-api" % "1.0.6", "com.weirddev" %% "scalalock-mongo" % "1.0.6" )
- Option B - if you're using reactivemongo
libraryDependencies ++= Seq( "com.weirddev" %% "scalalock-api" % "1.0.6", "com.weirddev" %% "scalalock-reactivemongo" % "1.1.0" //for reactivemongo 1.*
// "com.weirddev" %% "scalalock-reactivemongo" % "1.0.6" //for reactivemongo 0.* ) ```
-
wrap the block that should be synchronized across all nodes in cluster with
Lock#acquire()
method call- For
scalalock-mongo
(based onmongo-scala-driver
)
import com.mongodb.ConnectionString import com.weirddev.scalalock.mongo.MongoDistributedLock import org.mongodb.scala.{MongoClient, MongoClientSettings, MongoDatabase} import scala.concurrent.Future import scala.concurrent.duration._ protected val db: MongoDatabase = MongoClient(MongoClientSettings.builder() .applyConnectionString(new ConnectionString("mongodb://localhost:27017")) .build()).getDatabase("test") val distLock:Lock = new MongoDistributedLock(db) distLock.acquire("some_task_id", 10 minutes){ Future{ println("this block needs to execute in isolation across all application nodes in cluster") Thread.sleep(5000) "Task Completed" } }
- Alternatively, using
scalalock-reactivemongo
(based onorg.reactivemongo
)
import com.weirddev.scalalock.reactivemongo.ReactiveMongoDistributedLock import reactivemongo.api.{DefaultDB, MongoConnection, MongoDriver} import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future import scala.concurrent.duration._ private val mongoUri: String = "mongodb://localhost:27017/test" val driver = new MongoDriver val database: Future[DefaultDB] = for { uri <- Future.fromTry(MongoConnection.parseURI(mongoUri)) con = driver.connection(uri) dn <- Future(uri.db.get) db <- con.database(dn) } yield db val distLock = new ReactiveMongoDistributedLock(database) distLock.acquire("some_task_id", 10 minutes){ Future{ println("this block needs to execute in isolation across all application nodes in cluster") Thread.sleep(5000) "Task Completed" } }
- A simpler alternative using
scalalock-reactivemongo
in Play! Framework (add a dependency on reactivemongo play, i.e."org.reactivemongo" %% "play2-reactivemongo" % "0.16.5-play26"
)
import com.weirddev.scalalock.reactivemongo.ReactiveMongoDistributedLock import scala.concurrent.{ExecutionContext, Future} import scala.concurrent.duration._ import javax.inject.Inject import play.modules.reactivemongo.ReactiveMongoApi class MyRepository @Inject()(override val reactiveMongoApi: ReactiveMongoApi)(implicit val ec: ExecutionContext){ val distLock = new ReactiveMongoDistributedLock(reactiveMongoApi.database) distLock.acquire("some_task_id", 10 minutes){ Future{ println("this block needs to execute in isolation across all application nodes in cluster") Thread.sleep(5000) "Task Completed" } } }
- For
-
If you want to use the lock to synchronize task execution globally in a cluster and mandating a minimal interval - pass the
releaseLockWhenDone
asfalse
. This will keep the lock state as LOCKED even after task completion. Effectively keeping the lock until expiration - as set by theexpire
param. example:val result = mongoDistLock.acquire(resourceId = "test_task", expire = 30 minutes,releaseLockWhenDone = false){ println("After this block finishes to execute, the lock will retain for 30 minutes before any other task using resource id - test_task - could run again") Thread.sleep(5000) "Done" }
For other usage scenarios, review the integrative test code
Welcomed :) - Please refer to CONTRIBUTING.md
file.
Copyright (c) 2016 - 2024 WeirdDev. Licensed for free usage under the terms and conditions of Apache V2 - Apache V2 License.