0
votes

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
  ))
})
}
2
What is the type of processSteps ?Chetan Kumar Meena
Compose, rather wait for async (which make it sync and so ..)cchantep

2 Answers

1
votes

Few things you need to understand:

  1. 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.

  2. 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")
    }
1
votes

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.