2012-07-09 10 views
22

Sto tentando di implementare un processo in background di lunga esecuzione che viene generato quando un utente visita una pagina. Vorrei visualizzare l'avanzamento dell'attività proprio come in questo esempio: http://web.archive.org/web/20130122091205/http://www.lunatech-research.com/archives/2011/10/31/progressbar-jqueryui-websockets-playframeworkProcesso in esecuzione prolungata con barra di avanzamento Esempio PlayFramework 2

Qualcuno sa di un tutorial per PlayFramework 2.0 (utilizzando AKKA integrato)? Questo è per 1.2

risposta

21

Dopo aver letto tutta la documentazione di Akka per Java http://doc.akka.io/docs/akka/2.0.1/intro/getting-started-first-java.html ho trovato questo che sembra funzionare bene.

Il sistema funziona creando innanzitutto un attore unico per elaborare un "rapporto" (quando viene caricata la pagina di generazione). Questo attore genera un attore bambino che riporta i suoi progressi al genitore. L'attore genitore viene quindi interrogato tramite JavaScript per lo stato del thread secondario.

Una volta terminato, il bambino viene terminato e una volta che il genitore rileva che il bambino è finito, termina automaticamente.

Di seguito è riportato tutto il codice, sentitevi liberi di distruggermi se sono andato su questo nel modo sbagliato! (E 'OK per memorizzare lo stato in attori?!?)

Il codice di controllo:

public class Application extends Controller { 


public static Result generateReport() 
{ 
    //create akka job 

    //we should really create the actor with UUID name so that someone can't guess 
    //and use the API to view the status of other peoples jobs, it be fairly easy 
    //to guess as it goes $a,$b,$c etc... 
    ActorRef myActor = Akka.system().actorOf(new Props(MyGeneratorMaster.class)); 

    System.out.println(myActor.path()); 
    myActor.tell(new ConfigMessage("blarg message")); 

    return ok(generating.render("blarg","title",myActor.path().name())); 
} 

public static Result status(String uuid) 
{ 
    uuid = "akka://application/user/"+uuid; 
    ActorRef myActor = Akka.system().actorFor(uuid); 

    if(myActor.isTerminated()) 
    { 
       return ok("Report Generated - All Actors Terminated") ; 
    } 
    else 
    { 

     return async(
       Akka.asPromise(ask(myActor,new StatusMessage(), 3000)).map(
         new F.Function<Object,Result>() { 
          public Result apply(Object response) { 

           if(response instanceof ResultMessage) 
           { 
            return ok(((ResultMessage) response).getResult()); 
           } 
           return ok(response.toString()); 
          } 
         } 
       ) 
     ); 

    } 
} 

Il Master Attore:

public class MyGeneratorMaster extends UntypedActor { 

    private int completed = 0; 

    @Override 
    public void postStop() { 
     super.postStop(); 
     System.out.println("Master Killed"); 
    } 

    @Override 
    public void onReceive(Object message) throws Exception { 
     if (message instanceof actors.messages.ConfigMessage) { 
      ConfigMessage config = (ConfigMessage) message; 

      System.out.println("Received Config:" + config.getConfig()); 

      //Need to spawn child actor here.. 
      ActorRef child = this.getContext().actorOf(new Props(MyGeneratorChildWorker.class)); 

      //make the child thread do stuff 
      child.tell(new ConfigMessage("doSomething!")); 

      child.tell(akka.actor.PoisonPill.getInstance());//kill the child after the work is complete... 

     } else if (message instanceof StatusUpdate) { 
      System.out.println("Got Status Update"); 
      completed = ((StatusUpdate) message).getProgress(); 
     } else if (message instanceof StatusMessage) { 
      System.out.println("Got Status Message"); 
      getSender().tell(new ResultMessage("Status: " + completed + "%"), getSelf()); 

      if(completed == 100) 
      { 
       //kill this actor, we're done! 
       //could also call stop... 
       this.getSelf().tell(akka.actor.PoisonPill.getInstance()); 
      } 
     } else { 
      System.out.println("unhandled message"+message.toString()); 
      unhandled(message); 
     } 

    } 
} 

L'attore bambino:

public class MyGeneratorChildWorker extends UntypedActor { 

    @Override 
    public void postStop() { 
     super.postStop();  
     System.out.println("Child Killed"); 
    } 

    @Override 
    public void onReceive(Object message) throws Exception { 

     if (message instanceof ConfigMessage) { 

      System.out.println("Created Child Worker"); 

      System.out.println("Doing Work:"); 
      try { 

       for (int i = 0; i <= 100; i++) { 


        //update parent 
        this.context().parent().tell(new StatusUpdate(i)); 
        long j = 1; 
        //waste loads of cpu cycles 
        while (j < 1E8) { 
         j = j + 1; 
        } 
       } 
      } catch (Exception ex) { 

      } 
      System.out.println("Done Work:"); 


     } else 
      unhandled(message); 
    } 
} 

La pagina di visualizzazione con il polling lungo JavaScript:

@(message: String)(title: String)(id: String)@main(title) { 

<h2>@message</h2> 

     <script type="text/javascript"> 

      function getPercentage() 
      { 

       $.ajax({ 
        type: "GET", 
        url: "/status/@id", 
        dataType: "html", 
        success: function(html) 
         { 
         $('#status').html(html); 


         } 
       }); 

      } 

      $(document).ready(function() { 


      setInterval("getPercentage()",100); 
      }); 



     </script> 

     <div id="status"> 

     </div> 

} 
+2

Sembra buono, farò un tentativo. Il gioco è grandioso, ma cose come questa hanno campioni di codice molto piccoli. – Steve

+3

lo so, è molto frustrante! –

+1

"Va bene memorizzare lo stato in Actors?!?" Gli attori sono uno dei pochi posti in cui è bene memorizzare lo stato. – EECOLOR

Problemi correlati