Soumya Simanta
Soumya Simanta

Reputation: 11751

Dealing with Multiple Futures in Scala

I currently have a method that updates a Redis table based on a Future[String].

  def update(key: String, timeStamp: Long, jsonStringF: Future[String], redisClient: RedisClient) = {

    jsonStringF.map { jsonString =>
      val historyKey = "history." + key
      val tempKey = "temp." + key

      val tran = redisClient.transaction()
      tran.zadd(historyKey, (timeStamp, jsonString))
      tran.del(tempKey)
      val f = tran.exec()
      f.onComplete {
        case Success(suc) => dlogger.info(s"Updated $historyKey and deleted $tempKey successfully ....")
        case Failure(ex) => dlogger.warn(s"Error updating tables", ex)
      }
    }
  } 

Now I've two Future[String] (jsonStringF1 and jsonStringF2) and I want to update two different tables.

  def update(key: String, timeStamp: Long, jsonStringF1: Future[String], jsonStringF2: Future[String], redisClient: RedisClient) = {
 ....

}

I want to update another table ("another." + key) with String in jsonStringF2. How can I do that ?

UPDATE: Is the code below correct?

  def update(tableKey: String, timeStamp: Long,  jsonStringF1: Future[String], jsonStringF2: Future[String], redisClient: RedisClient) =
  {

    for {
      a <- jsonStringF1
      t <- jsonStringF2

      historyKey = "history." + tableKey
      anotherKey = "another." + tableKey + 

      tempKey = "temp." + tableKey
      tran = redisClient.transaction()
      _ = tran.zadd(historyKey, (timeStamp, a))
      _ = tran.zadd(anotherKey, (timeStamp, t))
      _ = tran.del(tempKey)
      f = tran.exec()
    } yield ()
  }

Upvotes: 2

Views: 184

Answers (3)

ktonga
ktonga

Reputation: 190

Since you have just 2 Futures you can zip them:

def update(tableKey: String, timeStamp: Long,  jsonStringF1: Future[String], jsonStringF2:Future[String], redisClient: RedisClient) = {

    val jsons = jsonStringF1.zip(jsonStringF2)
    jsons map {
      case (a, t) => 
        val historyKey = "history." + tableKey
        val anotherKey = "another." + tableKey

        val tran = redisClient.transaction()
        tran.zadd(historyKey, (timeStamp, a))
        tran.zadd(anotherKey, (timeStamp, t))
        tran.del(tempKey)
        tran.exec()
    }
}

Upvotes: 0

mavarazy
mavarazy

Reputation: 7735

  1. You can use for loop, as you described

    def update(tableKey: String, timeStamp: Long,  jsonStringF1: Future[String], jsonStringF2:Future[String], redisClient: RedisClient) = {
        for {
            a <- jsonStringF1
            t <- jsonStringF2
        } yield {
            val historyKey = "history." + tableKey
            val anotherKey = "another." + tableKey
    
            val tran = redisClient.transaction()
            tran.zadd(historyKey, (timeStamp, a))
            tran.zadd(anotherKey, (timeStamp, t))
            tran.del(tempKey)
            tran.exec()
        }
    }
    
  2. As an alternative to for you can also use scala/async (https://github.com/scala/async) and write your code like this

    def update(tableKey: String, timeStamp: Long,  jsonStringF1: Future[String], jsonStringF2:Future[String], redisClient: RedisClient) = {
        async {
            val a = await(jsonStringF1)
            val t = await(jsonStringF2)
    
            val historyKey = "history." + tableKey
            val anotherKey = "another." + tableKey
    
            val tran = redisClient.transaction()
            tran.zadd(historyKey, (timeStamp, a))
            tran.zadd(anotherKey, (timeStamp, t))
            tran.del(tempKey)
            tran.exec()
        }
    }
    

Which will also be nonblocking. Async has slight advantage, since

async blocks are compiled to a single anonymous class, as opposed to a separate anonymous class for each closure required at each generator.

Upvotes: 3

Spectre
Spectre

Reputation: 658

Your can collect multiple futures using a for:

val f1: Future[String] = ...
val f2: Future[String] = ...

for {
  a <- f1
  b <- f2
} {
  // Code to execute when both f1 and f2 complete
  // a and b are available here
}

Upvotes: 3

Related Questions