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

com.twitter.finagle.exp.FinagleScheduler.scala Maven / Gradle / Ivy

There is a newer version: 7.0.0
Show newest version
package com.twitter.finagle.exp

import com.twitter.app.GlobalFlag
import com.twitter.concurrent.{BridgedThreadPoolScheduler, LocalScheduler, Scheduler}
import com.twitter.finagle.stats.{DefaultStatsReceiver, Gauge, StatsReceiver}
import com.twitter.finagle.util.DefaultLogger
import com.twitter.jvm.numProcs
import java.util.concurrent.{LinkedTransferQueue, ThreadFactory, ThreadPoolExecutor, TimeUnit}
import scala.collection.mutable

object scheduler extends GlobalFlag[String](
  "local",
  "Which scheduler to use for futures "+
  " |  | [:] | [:]"
)

private[finagle] object FinagleScheduler {
  private val log = DefaultLogger

  private[this] val gauges = mutable.MutableList[Gauge]()

  private object Integer {
    def unapply(str: String): Option[Int] = {
      try {
        Some(str.toInt)
      } catch {
        case _: java.lang.NumberFormatException => None
      }
    }
  }

  private def switchToBridged(numWorkers: Int): Unit = {
    val queue = new LinkedTransferQueue[Runnable]()

    Scheduler.setUnsafe(new BridgedThreadPoolScheduler(
      "bridged scheduler",
      (threadFactory: ThreadFactory) => new ThreadPoolExecutor(
        numWorkers,
        numWorkers,
        0L,
        TimeUnit.MILLISECONDS,
        queue,
        threadFactory)))

    log.info("Using bridged scheduler with %d workers".format(numWorkers))
  }

  private def switchToForkJoin(numWorkers: Int): Unit = {
    log.info("Using forkjoin scheduler with %d workers".format(numWorkers))
    Scheduler.setUnsafe(
      new ForkJoinScheduler(numWorkers, DefaultStatsReceiver.scope("forkjoin")))
  }

  // exposed for testing
  private[exp] def addGauges(
    scheduler: Scheduler,
    statsReceiver: StatsReceiver,
    gauges: mutable.MutableList[Gauge]
  ): Unit = {
    gauges.synchronized {
      gauges += statsReceiver.addGauge("dispatches") {
        scheduler.numDispatches.toFloat
      }
      gauges += statsReceiver.addGauge("blocking_ms") {
        TimeUnit.NANOSECONDS.toMillis(scheduler.blockingTimeNanos)
      }
    }
  }

  def init(): Unit = {
    scheduler().split(":").toList match {
      case "bridged" :: Integer(numWorkers) :: Nil => switchToBridged(numWorkers)
      case "bridged" :: Nil => switchToBridged(numProcs().ceil.toInt)

      case "forkjoin" :: Integer(numWorkers) :: Nil => switchToForkJoin(numWorkers)
      case "forkjoin" :: Nil => switchToForkJoin(numProcs().ceil.toInt)

      case "lifo" :: Nil =>
        log.info("Using LIFO local scheduler")
        Scheduler.setUnsafe(new LocalScheduler(true))

      case "local" :: Nil => // do nothing
      case _ =>
        throw new IllegalArgumentException("Wrong scheduler config: %s".format(scheduler()))
    }

    addGauges(Scheduler, DefaultStatsReceiver.scope("scheduler"), gauges)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy