sydboraa sydboraa - 3 months ago 41
Scala Question

Do own stuff in Slick transaction

I'm using Slick 3.1.1 and i would like to implement my own stuff on Slick transaction.

def findSomeProducts = table.getSomeProducts() //db operation
def productTableUpdate = doSomeStuff1() //db operation
def priceTableUpdate = doSomeStuff2() //db operation

def updateElasticCache = updateIndexOfProduct() //this is not a database operation


I have these sample functions. Firstly, I'm getting some products from db and after i'm updating the tables. At the end I need to run updateElasticCache method. If updateElasticCache method fails, I would like to rollback whole db procceses.

I can't use
(for { ... } yield ()).transactionally
this code because it's not applicable for my cases. This 'transactionally' is waiting a db action. But I want to add another functionality which is not a db-process.

Is it possible? How can I achieve it?

Answer

DBIO.from

Yes !!! its possible to add non db logic in between db logic in slick using DBIO actions composition and DBIO.from

Note that "your own stuff" should return a future, future can be converted to DBIO and can be composed along with usual db actions.

DBIO.from can help you with this. Here is how it works. DBIO.from takes a future and converts it into a DBIOAction. now you can compose these actions with usual db actions to do non-db operations along with db operations in a transaction.

def updateElasticCache: Future[Unit] = Future(doSomething())

now lets say we have some db actions

def createUser(user: User): DBIO[Int] = ???

I want createUser to rollback if updating cache fails. so i do the following

val action = createUser.flatMap { _ => DBIO.from(updateElasticCache()) }.transactionally
db.run(action)

now if updateElasticCache fails whole tx will fail and everything will rollback to normal state.

Example

You can use for comprehension to make it look good

def updateStats: DBIO[Int] = ???
val rollbackActions =
  (for {
     cStatus <- createUser()
     uStatus <- updateStats()
     result <- DBIO.from(updateElasticCache())
   } yield result).transactionally
 db.run(rollbackActions)

everything roll backs if updateElasticCache future fails