Nebehr Gudahtt
Nebehr Gudahtt

Reputation: 189

Orphan Futures in Scala

Is there an idiomatic way to deal with side-effecting scala.concurrent.Future whose result is not really needed in the caller (i.e. neither success nor failure will be necessary to calculate the calling method's return value)? For example,

object XYZ {
  def log(s: String): Future[Unit] = ???
}

Is it correct to simply call XYZ.log("xyz") without any callbacks and proceed with the really important tasks? Won't this orphan Future be considered code smell? Any chance for it to be garbage collected before it is executed?

Upvotes: 2

Views: 190

Answers (2)

Mario Galic
Mario Galic

Reputation: 48430

When we have such Futures which are not part of main business logic but executed for their side effect, that is, represent a separate concern such as logging, then consider running them on a separate dedicated execution context. For example, create a separate pool with

val numOfThreads = 2
val threadPoolForSeparateConcerns = Executors.newFixedThreadPool(numOfThreads, (r: Runnable) => new Thread(r, s"thread-pool-for-separate-concerns-thread-${Random.nextInt(numOfThreads)}"))
val separateConcernsEc = ExecutionContext.fromExecutor(threadPoolForSeparateConcerns)

and then make sure to pass it in when running separate concerns

object XYZ {
  def log(s: String, ec: ExecutionContext): Future[Unit] = ???
}

XYZ.log("Failed to calculate 42", separateConcernsEc)

By separating main business logic thread pool, from thread pool for side-concerns, we minimise the chances of breaking main business logic through things like resource starvation etc.

Upvotes: 1

Alexey Romanov
Alexey Romanov

Reputation: 170899

Won't this orphan Future be considered code smell?

Not any more than any other discarded non-Unit value. Note that some people do consider any discarded value to be a code smell, which is why -Ywarn-value-discard and NonUnitStatements wart exist.

Any chance for it to be garbage collected before it is executed?

The Future object itself might be garbage collected, but it will submit a task to a thread pool which won't be (because the pool holds a reference to the task). Except cases like

def log(s: String): Future[Unit] = Future.just(())

of course.

Upvotes: 2

Related Questions