/http/src/main/scala/filodb/http/FiloHttpServer.scala

https://github.com/filodb/FiloDB · Scala · 73 lines · 54 code · 11 blank · 8 comment · 0 complexity · 97fa9fee3a6ab5dd94e0465b7c0ecc32 MD5 · raw file

  1. package filodb.http
  2. import scala.concurrent.{Await, Future}
  3. import scala.concurrent.duration.FiniteDuration
  4. import akka.actor.{ActorRef, ActorSystem}
  5. import akka.http.scaladsl.Http
  6. import akka.http.scaladsl.model.HttpResponse
  7. import akka.http.scaladsl.model.StatusCodes._
  8. import akka.http.scaladsl.server.Directives._
  9. import akka.http.scaladsl.server.ExceptionHandler
  10. import akka.http.scaladsl.server.Route
  11. import akka.stream.ActorMaterializer
  12. import com.typesafe.scalalogging.StrictLogging
  13. import filodb.coordinator.FilodbSettings
  14. trait FiloRoute {
  15. def route: Route
  16. }
  17. class FiloHttpServer(actorSystem: ActorSystem, filoSettings: FilodbSettings) extends StrictLogging {
  18. val settings = new HttpSettings(actorSystem.settings.config, filoSettings)
  19. private var binding: Http.ServerBinding = _
  20. def filoExceptionHandler: ExceptionHandler =
  21. ExceptionHandler {
  22. case ex: Exception =>
  23. extractUri { uri =>
  24. logger.error(s"Request to uri=$uri failed", ex)
  25. val errorString = s"Request to uri=$uri failed with ${ex.getClass.getName} ${ex.getMessage}\n" +
  26. ex.getStackTrace.map(_.toString).mkString("\n")
  27. complete(HttpResponse(InternalServerError, entity = errorString))
  28. }
  29. }
  30. /**
  31. * Starts the HTTP Server, blocks until it is up.
  32. *
  33. * @param coordinatorRef the ActorRef to the local NodeCoordinator
  34. * @param clusterProxy the ClusterSingletonProxy ActorRef to the NodeClusterActor singleton
  35. * @param externalRoutes Additional routes to add besides those configured within the module
  36. */
  37. def start(coordinatorRef: ActorRef,
  38. clusterProxy: ActorRef,
  39. externalRoutes: Route = reject): Unit = {
  40. implicit val system = actorSystem
  41. implicit val materializer = ActorMaterializer()
  42. // This is a preliminary implementation of routes. Will be enhanced later
  43. val filoRoutes: List[FiloRoute] = List(AdminRoutes,
  44. new ClusterApiRoute(clusterProxy),
  45. new HealthRoute(coordinatorRef),
  46. new PrometheusApiRoute(coordinatorRef, settings))
  47. val reduced = filoRoutes.foldLeft[Route](reject)((acc, r) => r.route ~ acc)
  48. val finalRoute = handleExceptions(filoExceptionHandler) {
  49. reduced ~ externalRoutes
  50. }
  51. val bindingFuture = Http().bindAndHandle(finalRoute,
  52. settings.httpServerBindHost,
  53. settings.httpServerBindPort)
  54. binding = Await.result(bindingFuture,
  55. scala.concurrent.duration.Duration.fromNanos(settings.httpServerStartTimeout.toNanos))
  56. logger.info("FiloDB HTTP server is live at http:/{}/", binding.localAddress)
  57. }
  58. def shutdown(hardDeadline: FiniteDuration): Future[Http.HttpTerminated] = {
  59. logger.info("Shutting down HTTP server")
  60. binding.terminate(hardDeadline)
  61. }
  62. }