Search code examples
scalapromiseakkafuturecancellation

Cancellation with Future and Promise in Scala


This is a followup to my previous question.

Suppose I have a task, which executes an interruptible blocking call. I would like to run it as a Future and cancel it with failure method of Promise.

I would like the cancel to work as follows:

  • If one cancels the task before it finished I would like the task to finish "immediately", interrupting the blocking call if it has already started and I would like the Future to invoke onFailure.

  • If one cancels the task after the task finished I would like to get a status saying that the cancel failed since the task already finished.

Does it make sense? Is it possible to implement in Scala? Are there any examples of such implementations?


Solution

  • scala.concurrent.Future is read-only, so one reader cannot mess things up for the other readers.

    It seems like you should be able to implement what you want as follows:

    def cancellableFuture[T](fun: Future[T] => T)(implicit ex: ExecutionContext): (Future[T], () => Boolean) = {
      val p = Promise[T]()
      val f = p.future
      p tryCompleteWith Future(fun(f))
      (f, () => p.tryFailure(new CancellationException))
    }
    
    val (f, cancel) = cancellableFuture( future => {
      while(!future.isCompleted) continueCalculation // isCompleted acts as our interrupted-flag
    
      result  // when we're done, return some result
    })
    
    val wasCancelled = cancel() // cancels the Future (sets its result to be a CancellationException conditionally)