From 135f80ba71454d777ceb0437175a50c16f7ac339 Mon Sep 17 00:00:00 2001 From: Aron Engineer <aron.engineer1@gmail.com> Date: Wed, 24 Feb 2021 21:23:07 +0000 Subject: [PATCH] WIP: Http endpoint added for health check --- akka-bbb-apps/project/Dependencies.scala | 8 ++++ .../scala/org/bigbluebutton/ApiService.scala | 31 +++++++++++++ .../main/scala/org/bigbluebutton/Boot.scala | 14 +++++- .../bigbluebutton/SystemConfiguration.scala | 4 ++ .../service/HealthzService.scala | 45 +++++++++++++++++++ .../src/universal/conf/application.conf | 4 +- 6 files changed, 103 insertions(+), 3 deletions(-) mode change 100644 => 100755 akka-bbb-apps/project/Dependencies.scala create mode 100755 akka-bbb-apps/src/main/scala/org/bigbluebutton/ApiService.scala create mode 100755 akka-bbb-apps/src/main/scala/org/bigbluebutton/service/HealthzService.scala diff --git a/akka-bbb-apps/project/Dependencies.scala b/akka-bbb-apps/project/Dependencies.scala old mode 100644 new mode 100755 index 576e5fb2a5..6e69b45e36 --- a/akka-bbb-apps/project/Dependencies.scala +++ b/akka-bbb-apps/project/Dependencies.scala @@ -14,6 +14,7 @@ object Dependencies { // Libraries val akkaVersion = "2.5.19" + val akkaHttpVersion = "10.1.4" val gson = "2.8.5" val jackson = "2.9.7" val logback = "1.2.3" @@ -47,6 +48,10 @@ object Dependencies { val commonsCodec = "commons-codec" % "commons-codec" % Versions.codec val sprayJson = "io.spray" % "spray-json_2.12" % Versions.spray + val akkaStream = "com.typesafe.akka" %% "akka-stream" % Versions.akkaVersion + val akkaHttp = "com.typesafe.akka" %% "akka-http" % Versions.akkaHttpVersion + val akkaHttpSprayJson = "com.typesafe.akka" %% "akka-http-spray-json" % Versions.akkaHttpVersion + val apacheLang = "org.apache.commons" % "commons-lang3" % Versions.lang val bbbCommons = "org.bigbluebutton" % "bbb-common-message_2.12" % Versions.bbbCommons excludeAll ( @@ -73,6 +78,7 @@ object Dependencies { Compile.scalaCompiler, Compile.akkaActor, Compile.akkaSl4fj, + Compile.akkaStream, Compile.googleGson, Compile.jacksonModule, Compile.quicklens, @@ -80,5 +86,7 @@ object Dependencies { Compile.commonsCodec, Compile.sprayJson, Compile.apacheLang, + Compile.akkaHttp, + Compile.akkaHttpSprayJson, Compile.bbbCommons) ++ testing } \ No newline at end of file diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/ApiService.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/ApiService.scala new file mode 100755 index 0000000000..df07205d50 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/ApiService.scala @@ -0,0 +1,31 @@ +package org.bigbluebutton + +import akka.http.scaladsl.model._ +import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport +import akka.http.scaladsl.server.Directives._ +import org.bigbluebutton.service.HealthzService +import spray.json.DefaultJsonProtocol + +case class HealthResponse(isHealthy: Boolean) + +trait JsonSupportProtocol extends SprayJsonSupport with DefaultJsonProtocol { + implicit val healthServiceJsonFormat = jsonFormat1(HealthResponse) +} + +class ApiService(healthz: HealthzService) extends JsonSupportProtocol { + + def routes = + path("healthz") { + get { + val future = healthz.getHealthz() + onSuccess(future) { + case response => + if (response.isHealthy) { + complete(StatusCodes.OK, HealthResponse(response.isHealthy)) + } else { + complete(StatusCodes.ServiceUnavailable, HealthResponse(response.isHealthy)) + } + } + } + } +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/Boot.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/Boot.scala index 6f1eb2b0be..f28b706626 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/Boot.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/Boot.scala @@ -1,5 +1,9 @@ package org.bigbluebutton +import akka.actor.ActorSystem +import akka.event.Logging +import akka.http.scaladsl.Http +import akka.stream.ActorMaterializer import org.bigbluebutton.common2.redis.{ MessageSender, RedisConfig, RedisPublisher } import org.bigbluebutton.core._ import org.bigbluebutton.core.bus._ @@ -8,13 +12,13 @@ import org.bigbluebutton.core2.AnalyticsActor import org.bigbluebutton.core2.FromAkkaAppsMsgSenderActor import org.bigbluebutton.endpoint.redis.AppsRedisSubscriberActor import org.bigbluebutton.endpoint.redis.RedisRecorderActor -import akka.actor.ActorSystem -import akka.event.Logging import org.bigbluebutton.common2.bus.IncomingJsonMessageBus +import org.bigbluebutton.service.HealthzService object Boot extends App with SystemConfiguration { implicit val system = ActorSystem("bigbluebutton-apps-system") + implicit val materializer: ActorMaterializer = ActorMaterializer() implicit val executor = system.dispatcher val logger = Logging(system, getClass) @@ -75,4 +79,10 @@ object Boot extends App with SystemConfiguration { ), "redis-subscriber" ) + + val healthz = HealthzService(system) + + val apiService = new ApiService(healthz) + + val bindingFuture = Http().bindAndHandle(apiService.routes, httpHost, httpPort) } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala index 54c67fecf2..640e516aad 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala @@ -74,4 +74,8 @@ trait SystemConfiguration { lazy val toAkkaTranscodeJsonChannel = Try(config.getString("eventBus.toAkkaTranscodeJsonChannel")).getOrElse("to-akka-transcode-json-channel") lazy val fromAkkaTranscodeJsonChannel = Try(config.getString("eventBus.fromAkkaTranscodeJsonChannel")).getOrElse("from-akka-transcode-json-channel") + // Grab the "interface" parameter from the http config + val httpHost = config.getString("http.interface") + // Grab the "port" parameter from the http config + val httpPort = config.getInt("http.port") } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/service/HealthzService.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/service/HealthzService.scala new file mode 100755 index 0000000000..2e07689b41 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/service/HealthzService.scala @@ -0,0 +1,45 @@ +package org.bigbluebutton.service + +import akka.actor.{ Actor, ActorLogging, ActorSystem, Props } +import akka.util.Timeout + +import scala.concurrent.Future +import scala.concurrent.duration.DurationInt +import akka.pattern.{ AskTimeoutException, ask } + +sealed trait HealthMessage + +case object GetHealthMessage extends HealthMessage +case class GetHealthResponseMessage(isHealthy: Boolean) extends HealthMessage + +object HealthzService { + def apply(system: ActorSystem) = new HealthzService(system) +} + +class HealthzService(system: ActorSystem) { + implicit def executionContext = system.dispatcher + implicit val timeout: Timeout = 2 seconds + + val actorRef = system.actorOf(HealthzActor.props()) + + def getHealthz(): Future[GetHealthResponseMessage] = { + val future = actorRef.ask(GetHealthMessage).mapTo[GetHealthResponseMessage] + future.recover { + case e: AskTimeoutException => { + GetHealthResponseMessage(isHealthy = false) + } + } + } + +} + +object HealthzActor { + def props(): Props = Props(classOf[HealthzActor]) +} + +class HealthzActor extends Actor with ActorLogging { + override def receive: Receive = { + case GetHealthMessage => sender ! GetHealthResponseMessage(isHealthy = true) + case _ => println("unexpected message, exception could be raised") + } +} \ No newline at end of file diff --git a/akka-bbb-apps/src/universal/conf/application.conf b/akka-bbb-apps/src/universal/conf/application.conf index 564b152038..00d19d3a65 100755 --- a/akka-bbb-apps/src/universal/conf/application.conf +++ b/akka-bbb-apps/src/universal/conf/application.conf @@ -61,7 +61,9 @@ eventBus { http { interface = "127.0.0.1" - port = 9999 + interface = ${?INTERFACE} + port = 8901 + port = ${?PORT} } services { -- GitLab