Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to carry on executing Future sequence despite failure?

Tags:

The traverse method from Future object stops at first failure. I want a tolerant/forgiving version of this method which on occurrence of errors carries on with the rest of the sequence.

Currently we have added the following method to our utils:

def traverseFilteringErrors[A, B <: AnyRef]                            (seq: Seq[A])                            (f: A => Future[B]): Future[Seq[B]] = {   val sentinelValue = null.asInstanceOf[B]   val allResults = Future.traverse(seq) { x =>     f(x) recover { case _ => sentinelValue }   }   val successfulResults = allResults map { result =>     result.filterNot(_ == sentinelValue)   }   successfulResults } 

Is there a better way to do this?

like image 999
missingfaktor Avatar asked Apr 02 '13 22:04

missingfaktor


People also ask

Does future sequence preserve order?

Michi. Apparently Future. sequence does preserve the order, but the API documentation does not state this anywhere.

What is a promise Scala?

Promise is an object which can be completed with a value or failed with an exception. A promise should always eventually be completed, whether for success or failure, in order to avoid unintended resource retention for any associated Futures' callbacks or transformations. Source Promise.scala. AnyRef, Any. Promise.

What is Scala Futures?

Future represents a result of an asynchronous computation that may or may not be available yet. When we create a new Future, Scala spawns a new thread and executes its code. Once the execution is finished, the result of the computation (value or exception) will be assigned to the Future.

Why do companies fail to execute their strategies?

But only solid execution keeps you there. Unfortunately, most companies struggle with implementation. That’s because they overrely on structural changes, such as reorganization, to execute their strategy. Though structural change has its place in execution, it produces only short-term gains.

What is the most important factor in strategy execution?

What Matters Most to Strategy Execution. When a company fails to execute its strategy, the first thing managers often think to do is restructure. But our research shows that the fundamentals of good execution start with clarifying decision rights and making sure information flows where it needs to go.

How hard is it to successfully execute a good strategy?

The simple answer would be that successfully executing a good strategy is just exceptionally hard. But that is hardly a gratifying answer. There are many other things that are exceptionally hard, but where we succeed nevertheless.

Why is it important to execute a plan?

The act of executing a plan is fundamental in any project. It’s one of the paramount actions that a leader, project manager or team leader is responsible for. That said, when executing a plan, it’s rare that everything goes according to that plan.


1 Answers

A genuinely useful thing (generally speaking) would be to be able to promote the error of a future into a proper value. Or in other words, transform a Future[T] into a Future[Try[T]] (the succesful return value becomes a Success[T] while the failure case becomes a Failure[T]). Here is how we might implement it:

// Can also be done more concisely (but less efficiently) as: // f.map(Success(_)).recover{ case t: Throwable => Failure( t ) } // NOTE: you might also want to move this into an enrichment class def mapValue[T]( f: Future[T] ): Future[Try[T]] = {   val prom = Promise[Try[T]]()   f onComplete prom.success   prom.future } 

Now, if you do the following:

Future.traverse(seq)( f andThen mapValue ) 

You'll obtain a succesful Future[Seq[Try[A]]], whose eventual value contains a Success instance for each successful future, and a Failure instance for each failed future. If needed, you can then use collect on this seq to drop the Failure instances and keep only the sucessful values.

In other words, you can rewrite your helper method as follows:

def traverseFilteringErrors[A, B](seq: Seq[A])(f: A => Future[B]): Future[Seq[B]] = {   Future.traverse( seq )( f andThen mapValue ) map ( _ collect{ case Success( x ) => x } ) } 
like image 80
Régis Jean-Gilles Avatar answered Nov 25 '22 12:11

Régis Jean-Gilles