Home > Software design >  Akka server stops immediately after running
Akka server stops immediately after running

Time:12-31

I'm trying to set up a simple akka-grpc server as it's done in the documentation.

migrationResult match {
  case Left(exception) => system.log.error(exception, "Exception while migrating schema", exception)
  case Right(_) =>
    system.log.info(s"Schema migrated with success")
    val registerService: HttpRequest => Future[HttpResponse] =
      RegisterServiceHandler(new RegisterImpl())

      Http().newServerAt(interface = "0.0.0.0", port = port).bind(registerService)

}

Problem is that it stops immediately after running, it does not listen for any call. The service implementation (RegisterImpl) looks like this

class RegisterImpl(implicit mat: Materializer) extends RegisterService with LazyLogging {
  import mat.executionContext
  override def registerUser(request: RegisterRequest): Future[RegisterResponse] = {
    val credentials = UserCredentials(UUID.randomUUID(), request.username, request.emailAddress, request.password)
    val user = User(None, request.fullName, request.city, request.address, request.neighborhood, credentials)

    val responseIO = for {
      _ <- userRepository.insertUser(user)
    } yield ()

    responseIO.attempt.unsafeRunSync() match {
      case Right(_) =>
        Future.successful(new RegisterResponse(true))
      case Left(e) =>
        logger.error(s"User registration failed because of error: ${e.getMessage}")
        Future.successful(new RegisterResponse(false))
    }
  }

CodePudding user response:

I am suspecting that your blocking code (using runUnsafeSync, mapping Either to Future synchronously) is to blame for it.

// This is blocking current thread
responseIO.attempt.unsafeRunSync() match {
  // These 2 create Futures, but only after blocking is released
  // by the finished IO computation (if it finishes...)
  case Right(_) =>
    Future.successful(new RegisterResponse(true))
  case Left(e) =>
    logger.error(s"User registration failed because of error: ${e.getMessage}")
    Future.successful(new RegisterResponse(false))
}
// You'd have to use
//   Future { blocking { ... } }
// instead of match   Future.successful to be async
// (and inform Future's thread pool that you are blocking)
// (but it still could lead to a deadlock or worse performance).

There would be several ways to deal with it (using Future { ... } with blocking, debugging thread pools), but I would suggest implementing your service as:

responseIO.attempt.map {
  case Right(_) =>
    new RegisterResponse(true)
  case Left(e) =>
    logger.error(s"User registration failed because of error: ${e.getMessage}")
    new RegisterResponse(false)
}.unsafeToFuture // IO knows how to create a Future without issues

to make sure that conversion to Future is handled by IO itself without needless blocking.

CodePudding user response:

It seems the problem was related to sbt and not to akka or implementation, I've just changed sbt version from build.properties from 1.6.1 to 1.5.2, still not sure what went wrong with the newer version

  • Related