Le problème est, une fois que vous commencez à parler à Futures
, vous devez continuer à parler dans Futures
, l'idée est que le même serveur traitera tout ce temps d'attente et les changements de contexte, donc jouer l'auto peut gérer votre promets qu'à un certain piont, vous retournerez un résultat. Ainsi, au lieu d'appeler des fonctions dans vos contrôleurs qui renvoient un Any
, le jeu peut gérer Future[Any]
.
val weight: Future[String] = getInfo() map { response =>
if (response.toString().length > 0) (response \ "weight").as[String])
else throw new Exception("didn't get response")
}
Si vous avez plusieurs appels futurs, où chacun a besoin le résultat d'un autre avenir, vous pouvez utiliser Pour une meilleure compréhension pour éviter l'enfer de la carte. Par exemple, voici un petit exemple plus complexe:
def processSync(databaseServer: DatabaseServer, databaseIdentity: DatabaseIdentity): Future[String] = {
val info = for {
catalogs <- databaseSyncService.getCatalogs(databaseServer.address, databaseServer.port, databaseIdentity.login, databaseIdentity.password)
clubbers <- getClubbers(databaseServer.id)
ignoredCatalogs <- ignoredCatalogService.get(databaseServer.id)
} yield (catalogs, clubbers, ignoredCatalogs)
val result = info.map{
case(catalogs, clubbers, ignoredCatalogs) => {
val currentCatalogs = (clubbers.map(clubber =>
Seq(Some(clubber.mainSchema), clubber.archiveSchema, clubber.blacklistSchema, clubber.logsSchema).flatten
).flatten ++ ignoredCatalogs).toSet
val serverCatalogs = catalogs.toSet
if(currentCatalogs == serverCatalogs) {
"synchronized"
} else {
"outOfSync"
}
}
}.recover{
case sqlE: SQLServerException =>{
logger.error(s"Conection error with ${databaseServer.name}", sqlE)
"connectionError"
}
}
for{
realResult <- result
_ <- databaseServerRepo.updateSync(databaseServer.id, realResult)
} yield realResult
}
Chaque valeur dans le pour un avenir, mais ci-dessous, nous pouvons accéder à leur valeur, à la fin du pour, vous utilisez le rendement pour marquer ce besoin de être retourné.
Autre exemple pourrait être cet appel du contrôleur (ignorer la partie shilouete, est une bibliothèque d'authentification, pensez simplement du type de retour comme un avenir [Résultat]):
def sync(id: Int) = silhouette.SecuredAction.async { implicit request: SecuredRequest[DefaultEnv, AnyContent] =>
val actions = for {
(server, identity) <- databaseServerService.getWithIdentity(id)
databaseCatalogs <- databaseSyncService.getCatalogs(server.address, server.port, identity.login, identity.password)
ignoredCatalogs <- ignoredCatalogService.get(id)
clubberIntegrations <- clubberIntegrationService.getClubbersListOrAutoFill(id, databaseCatalogs, ignoredCatalogs.map(_.name))
} yield Future.successful {
val catalogs = databaseCatalogs.map { x =>
val ignoredCatalogNotes = ignoredCatalogs.filter(_.name == x).map(_.note).headOption
DatabaseCatalog(x, ignoredCatalogNotes.getOrElse(""), ignoredCatalogNotes.isDefined)
}
Ok(web.databaseserver.views.html.databaseServerSync(request.identity, server, DatabaseServerForSync(clubberIntegrations, catalogs)))
}
actions.recover {
case _: SQLServerException => {
databaseServerService.getName(id).map(x => {
Redirect(web.databaseserver.controllers.routes.DatabaseServerController.list())
.flashing("error" -> Messages("databaseSync.couldNotConnect", x))
})
}
}.flatMap(x => x)
}
, j'ai oublié de mentionner également, Si vous avez besoin de gérer une fonction qui utilise un avenir et d'autres ne pas, vous pouvez transformer ce dernier avec Future.successful
, il est également Future.sequence
pour convertir un Seq[Future[Any]]
en Future[Seq[Any]]
et d'autres fonctions pour vous aider à gérer les futurs de différentes manières.