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

com.twitter.scrooge.OstrichThriftServer.scala Maven / Gradle / Ivy

The newest version!
package com.twitter.scrooge

import com.twitter.app.GlobalFlag
import com.twitter.conversions.time._
import com.twitter.finagle.builder.{Server, ServerBuilder}
import com.twitter.finagle.stats.{StatsReceiver, OstrichStatsReceiver}
import com.twitter.finagle.ThriftMux
import com.twitter.finagle.thrift.{Protocols, ThriftServerFramedCodec}
import com.twitter.finagle.tracing.{DefaultTracer, Tracer}
import com.twitter.finagle.Service
import com.twitter.logging.Logger
import com.twitter.ostrich
import com.twitter.util.Duration
import java.net.InetSocketAddress
import java.util.concurrent.atomic.AtomicReference
import org.apache.thrift.protocol.TProtocolFactory

/**
 * A [[com.twitter.app.GlobalFlag]] for enabling use of ThriftMux.
 */
object enableThriftMuxServer
  extends GlobalFlag(false, "If set to true, Thrift server will be served over ThriftMux")

/**
 * This trait is intended as a near-drop-in replacement for the ThriftServer class generated by
 * scrooge, which will soon no longer generated. Most use-cases are covered by simply changing
 * a class declaration that looks like "X extends Y.ThriftServer" to
 * "X extends Y.FutureIface with OstrichThriftServer".
 *
 * Ostrich in general is now deprecated, and long-term, you should switch to twitter-server.
 */
trait OstrichThriftServer extends ostrich.admin.Service {
  val log = Logger.get(getClass)

  def thriftCodec = ThriftServerFramedCodec()
  def statsReceiver: StatsReceiver = new OstrichStatsReceiver
  def tracer: Tracer = DefaultTracer
  @deprecated("use tracer instead", "3.3.3")
  def tracerFactory: Tracer.Factory = () => DefaultTracer
  val thriftProtocolFactory: TProtocolFactory = Protocols.binaryFactory()
  val thriftPort: Int
  val serverName: String

  protected def finagleService: Service[Array[Byte], Array[Byte]] =
    findFutureIface(getClass) match {
      case None => throw new IllegalStateException("Can't infer Service class, you must implement finagleService method")
      case Some(iface) =>
        val serviceName = iface.getName.dropRight(12) + "$FinagledService"
        val serviceClass = Class.forName(serviceName)
        val constructor = serviceClass.getConstructor(iface, classOf[TProtocolFactory])
        constructor.newInstance(this, thriftProtocolFactory)
          .asInstanceOf[Service[Array[Byte], Array[Byte]]]
    }

  private def findFutureIface(cls: Class[_]): scala.Option[Class[_]] =
    if (cls.getName.endsWith("$FutureIface"))
      Some(cls)
    else
      (scala.Option(cls.getSuperclass) ++ cls.getInterfaces).view.flatMap(findFutureIface).headOption

  // Must be thread-safe as different threads can start and shutdown the service.
  private[this] val _server = new AtomicReference[Server]
  def server = _server.get
  def server_=(value: Server) = _server.set(value)

  def start() {
    server_=(serverBuilder.build(finagleService))
  }

  /**
   * You can override this to provide additional configuration
   * to the ServerBuilder.
   */
  def serverBuilder = {
    val baseBuilder =
      if (enableThriftMuxServer()) {
        log.info("Configuring server to use ThriftMux")
        ServerBuilder().stack(ThriftMux.server)
      } else {
        ServerBuilder().codec(thriftCodec)
      }

    baseBuilder.name(serverName)
      .reportTo(statsReceiver)
      .bindTo(new InetSocketAddress(thriftPort))
      .tracer(tracer)
  }

  /**
   * Close the underlying server gracefully with the given grace
   * period. close() will drain the current channels, waiting up to
   * ``timeout``, after which channels are forcibly closed.
   */
  def shutdown(timeout: Duration = 0.seconds) {
    synchronized {
      val s = server
      if (s != null) {
        s.close(timeout)
      }
    }
  }

  def shutdown() = shutdown(0.seconds)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy