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

com.twitter.server.Lifecycle.scala Maven / Gradle / Ivy

There is a newer version: 18.9.1
Show newest version
package com.twitter.server

import com.twitter.app.{GlobalFlag, App}
import com.twitter.finagle.http.HttpMuxer
import com.twitter.server.handler._
import java.lang.management.ManagementFactory
import java.util.concurrent.atomic.AtomicBoolean
import scala.collection.JavaConverters._

trait Lifecycle { self: App =>
  // Mesos/Aurora lifecycle endpoints
  HttpMuxer.addHandler("/abortabortabort", new AbortHandler)
  HttpMuxer.addHandler("/quitquitquit", new ShutdownHandler(this))
  HttpMuxer.addHandler("/health", new ReplyHandler("OK\n"))
}

object promoteBeforeServing extends GlobalFlag[Boolean](true,
  "Promote objects in young generation to old generation before serving requests. " +
    "May shorten the following gc pauses by avoiding the copying back and forth between survivor " +
    "spaces of a service's long lived objects.")

object Lifecycle {

  private[server] class PromoteToOldGen(
      runtimeArgs: Seq[String] = ManagementFactory.getRuntimeMXBean.getInputArguments.asScala)
  {
    private[this] val hasPromoted = new AtomicBoolean(false)

    private[server] def promoted: Boolean = hasPromoted.get()

    /**
     * Depending on the VM flags used, `System.gc` will not have the effect we want.
     */
    private[this] def shouldExplicitGc: Boolean = {
      !runtimeArgs.contains("-XX:+ExplicitGCInvokesConcurrent")
    }

    /**
     * Helps make early gc pauses more consistent.
     *
     * Ideally this runs in the moments right before your service starts accepting traffic.
     */
    def beforeServing(): Unit = {
      if (promoteBeforeServing() && shouldExplicitGc && hasPromoted.compareAndSet(false, true)) {
        // This relies on the side-effect of a full gc that all objects in the
        // young generation are promoted to the old generation.
        // If this side-effect were to disappear in a future version
        // of the jdk, it would not be disastrous. However, then we may choose
        // to add a `System.promoteAllLiveObjects()` hook.
        System.gc()
      }
    }
  }

  /**
   * Give the application control over when to present to Mesos as being ready
   * for traffic. When the method `warmupComplete()` is invoked, the application
   * is considered ready.
   * @note Mesos doesn't gate traffic on /health so all pre-bind warmup needs to
   *       happen in `prebindWarmup()`
   */
  trait Warmup {
    HttpMuxer.addHandler("/health", new ReplyHandler(""))

    /**
     * Prebind warmup code. Used for warmup tasks that we want to run before we
     * accept traffic.
     */
    def prebindWarmup(): Unit = {
      new PromoteToOldGen().beforeServing()
    }

    /**
     * The service is bound to a port and warmed up, announce health.
     */
    def warmupComplete(): Unit = {
      HttpMuxer.addHandler("/health", new ReplyHandler("OK\n"))
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy