All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jp.co.bizreach.elasticsearch4s.retry.FutureRetryManager.scala Maven / Gradle / Ivy

The newest version!
package jp.co.bizreach.elasticsearch4s.retry

import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.atomic.AtomicBoolean
import java.util.function.Consumer

import scala.concurrent.{ExecutionContext, Future, Promise}
import scala.util.{Failure, Success}

class FutureRetryManager {

  private val tasks = new ConcurrentLinkedQueue[FutureRetryTask]()

  private val running = new AtomicBoolean(true)

  private val thread = new Thread {
    override def run(): Unit = {
      while(running.get()){
        val currentTime = System.currentTimeMillis
        tasks.iterator().forEachRemaining(new Consumer[FutureRetryTask]{ // TODO Not use partial function for Scala 2.11 cross build
          override def accept(task: FutureRetryTask): Unit = {
            if (task.nextRun <= currentTime) {
              tasks.remove(task)
              val future = task.f()
              future.onComplete {
                case Success(v) => task.promise.success(v)
                case Failure(e) => {
                  if (task.count == task.config.maxAttempts) {
                    task.promise.failure(e)
                  } else {
                    val count = task.count + 1
                    val nextRun = currentTime + task.config.backOff.nextDuration(count, task.config.retryDuration.toMillis)
                    tasks.add(new FutureRetryTask(task.f, task.config, task.ec, task.promise, nextRun, count))
                  }
                }
              }(task.ec)
            }
          }
        })
        Thread.sleep(100)
      }
    }
  }

  thread.start()

  def scheduleFuture[T](f: => Future[T])(implicit config: RetryConfig, ec: ExecutionContext): Future[T] = {
    val promise = Promise[T]()
    val task = new FutureRetryTask(() => f, config, ec, promise.asInstanceOf[Promise[Any]], System.currentTimeMillis + config.retryDuration.toMillis)
    tasks.add(task)
    promise.future
  }

  def shutdown(): Unit = {
    running.set(false)
  }

}

private[retry] class FutureRetryTask(
  val f: () => Future[Any],
  val config: RetryConfig,
  val ec: ExecutionContext,
  val promise: Promise[Any],
  val nextRun: Long,
  val count: Int = 1
)




© 2015 - 2025 Weber Informatics LLC | Privacy Policy