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