Reputation: 5629
again I have a problem with asyncronousity of scala.
I have the following code:
Future.sequence {
processSteps.map { step =>
val prerequisiteFuture = processStepPrerequisitesDTO.getProcessStepPrerequisiteIdsByProcessTemplateIdSeq(step.id.get)
prerequisiteFuture.map(prereqs => {
step.prerequisites = Some(prereqs)
println("COPY", step.prerequisites)
})
}
}
processSteps.map { step => {
println("diddled", step.prerequisites)}
}
How can I properly wait for the future.sequnce to be finished. Because whenI try to print them afterwards its empty ... but its not ... the lines are called at the same time and print is faster than the future.sequence.
I don't want to use Await ...
thanks.
UPDATE
Here is my full controller function: def getEditProcessTemplateData(processTemplateId: Int): Action[AnyContent] = Action.async { //Get all steps of this process templates val stepIds: Future[Seq[Int]] = processTemplateDTO.getProcessStepTemplateIds(processTemplateId)
val process = for {
allApprovedProcessTemplates <- processTemplateDTO.getApprovedProcessTemplates //Get all approved process templates
processTemplate <- processTemplateDTO.getProcessTemplate(processTemplateId) // Get the Process Template
prerequisites <- getProcessTemplateForEdit(processPrerequisitesDTO.getProcessPrerequisiteProcessTemplateIdsByProcessTemplateId(processTemplateId))
postConditions <- getProcessTemplateForEdit(processPostConditionsDTO.getProcessPostConditionProcessTemplateIdsByProcessTemplateId(processTemplateId))
approvedProcessTemplate <- processTemplateDTO.getProcessTemplate(processTemplate.get.approveprocess)
trainedProcessTemplate <- processTemplateDTO.getProcessTemplate(processTemplate.get.trainingsprocess)
processSteps <- processTemplateDTO.getProcessStepTemplates(processTemplateId)
// Step prerequisites
processStepsPrerequisites <- getProcessStepsPrerequisites(stepIds)
processStepsPrerequisiteProcessTemplate <- getProcessStepsPrerequisiteProcessTemplate(stepIds)
processTemplatesForStepPrerequisites <- getProcessTemplateForStepPrerequisite(stepIds)
// Step post conditions
processStepsPostConditions <- getProcessStepsPostConditions(stepIds)
processStepPostConditionProcessTemplate <- getProcessStepPostConditionProcessTemplate(stepIds)
processTemplatesForStepPostConditions <- getProcessTemplateForStepPostCondition(stepIds)
// Derived processes
derivedProcesses <- getDerivedProcesses(stepIds)
processTemplatesForStepDerivedProcesses <- getProcessStepsDerivedProcesses(stepIds)
// Process to process step
processStepsTemplates_ProcessTemplates <- getProcessStepsTemplates_ProcessTemplates(stepIds)
processTemplatesForProcessTemplatesToProcessStep <- getProcessTemplateToProcessStepId(stepIds)
responsible <- raciProcessTemplateDTO.getResponsibleProcessTemplates(processTemplateId) // get all responsibles for this process template
accountable <- raciProcessTemplateDTO.getAccountableProcessTemplates(processTemplateId) // get all accountables for this process template
consulted <- raciProcessTemplateDTO.getConsultedProcessTemplates(processTemplateId) // get all consulted for this process template
informed <- raciProcessTemplateDTO.getInformedProcessTemplates(processTemplateId) // get all consulted for this process template
} yield (allApprovedProcessTemplates, processTemplate, prerequisites, postConditions, processSteps, processStepsPrerequisites,
processStepsPrerequisiteProcessTemplate, processTemplatesForStepPrerequisites, processStepsPostConditions, processStepPostConditionProcessTemplate, processTemplatesForStepPostConditions, derivedProcesses,
processTemplatesForStepDerivedProcesses, processStepsTemplates_ProcessTemplates, processTemplatesForProcessTemplatesToProcessStep, approvedProcessTemplate, trainedProcessTemplate, responsible, accountable, consulted, informed)
process.map({ case (allApprovedProcessTemplates, processTemplate, prerequisites, postConditions, processSteps, processStepsPrerequisites,
processStepsPrerequisiteProcessTemplate, processTemplatesForStepPrerequisites, processStepsPostConditions, processStepPostConditionProcessTemplate, processTemplatesForStepPostConditions, derivedProcesses,
processTemplatesForStepDerivedProcesses, processStepsTemplates_ProcessTemplates, processTemplatesForProcessTemplatesToProcessStep, approvedProcessTemplate, trainedProcessTemplate, responsible, accountable, consulted, informed) =>
val sequenced = Future.sequence {
processSteps.map { step =>
val prerequisiteFuture = processStepPrerequisitesDTO.getProcessStepPrerequisiteIdsByProcessTemplateIdSeq(step.id.get)
prerequisiteFuture.map(prereqs => {
step.prerequisites = Some(prereqs)
println("COPY", step.prerequisites)
})
}
}
sequenced.map { items => {
println(items)}
}
Ok(Json.obj(
"allApprovedProcessTemplates" -> allApprovedProcessTemplates,
"processTemplate" -> processTemplate,
"prerequisites" -> prerequisites,
"postConditions" -> postConditions,
"approvedProcessTemplate" -> approvedProcessTemplate,
"trainedProcessTemplate" -> trainedProcessTemplate,
// Step prerequisites
"processStepsPrerequisites" -> processStepsPrerequisites,
"processStepsPrerequisiteProcessTemplate" -> processStepsPrerequisiteProcessTemplate,
"processTemplatesForStepPrerequisites" -> processTemplatesForStepPrerequisites,
// Step post conditions
"processStepsPostConditions" -> processStepsPostConditions,
"processStepPostConditionProcessTemplate" -> processStepPostConditionProcessTemplate,
"processTemplatesForStepPostConditions" -> processTemplatesForStepPostConditions,
// Derived processes
"derivedProcesses" -> derivedProcesses,
"processTemplatesForStepDerivedProcesses" -> processTemplatesForStepDerivedProcesses,
// Process to process step
"processStepsTemplates_ProcessTemplates" -> processStepsTemplates_ProcessTemplates,
"processTemplatesForProcessTemplatesToProcessStep" -> processTemplatesForProcessTemplatesToProcessStep,
"steps" -> processSteps,
"responsible" -> responsible,
"accountable" -> accountable,
"consulted" -> consulted,
"informed" -> informed
))
})
}
Upvotes: 0
Views: 254
Reputation: 354
Few things you need to understand:
The return type of a function/lambda is defined by the last statement of the function, if there are no return statements in the function. So the function
prerequisiteFuture.map(prereqs => {
step.prerequisites = Some(prereqs)
println("COPY", step.prerequisites)
})
will return Future[Unit], since return type of println() is Unit.
Future.sequence converts List[Future[A]]
to Future[List[A]]
.
So in the above example you have created a future that will print but won't return anything. And later you are just printing the steps.
Since future are delayed the output will be diddled
followed by COPY
.
If you want to execute diddled after the Copy you should use future.map()
. Like this
Future.sequence {processSteps.map {
step =>
val prerequisiteFuture = processStepPrerequisitesDTO
.getProcessStepPrerequisiteIdsByProcessTemplateIdSeq(step.id.get)
prerequisiteFuture.map(prereqs => {
step.prerequisites = Some(prereqs)
println("COPY", step.prerequisites)
step.prerequisites
})
}
}.map {
items =>
items.map { step =>
println("diddled", step.prerequisites)
}
Ok("your json response here")
}
Upvotes: 1
Reputation: 3435
Could you try this:
val sequenced = Future.sequence {
processSteps.map { step =>
val prerequisiteFuture = processStepPrerequisitesDTO.getProcessStepPrerequisiteIdsByProcessTemplateIdSeq(step.id.get)
prerequisiteFuture.map(prereqs => {
step.prerequisites = Some(prereqs)
println("COPY", step.prerequisites)
})
}
}
sequenced.map { items =>
items foreach (println("diddled", _.prerequisites))
}
?
-------------------------------------UPDATE-------------------------
You are not providing any context on where this place of code is really running in. So if you want it to be eventually printed in console you do need to make sure that main thread or whatever thread you have there is still running when all futures in the sequence are completed. Here is a simplified example: import scala.concurrent.Future import scala.concurrent.ExecutionContext.Implicits.global
object Test {
def main(args:Array[String]):Unit = {
val sequence = Seq(Future({Thread.sleep(100); 1}), Future({Thread.sleep(200); 2}))
val sequenced = Future.sequence(sequence)
sequenced foreach(items => items foreach(println(_)))
Thread.sleep(1000)
}
}
Which produces following console output:
1
2
Process finished with exit code 0
But use of Thread.sleep
or Await
in this example is only needed for showing the results in the console.
You initial problem was that you wrapped the seq of futures into Future.sequence
but after that you still tried to work with the internal seq, you never used created by Future.sequence
instance of the future.
I think that in your code you pass the resulting future to some higher context so you need to check and println
there if this is e.g. the web-app.
If taking everything above into consideration it still prints empty vector - then it means that the vector is indeed empty so you need to debug locally and find out why.
Upvotes: 1