2012-07-09 9 views
22

Estoy tratando de implementar un proceso de fondo de larga ejecución que se genera cuando un usuario visita una página. Me gustaría mostrar el progreso de la tarea como en este ejemplo: http://web.archive.org/web/20130122091205/http://www.lunatech-research.com/archives/2011/10/31/progressbar-jqueryui-websockets-playframeworkProceso de ejecución larga con barra de progreso Ejemplo PlayFramework 2

¿Alguien sabe de un tutorial para PlayFramework 2.0 (utilizando AKKA incorporado)? Este es para 1.2

Respuesta

21

Después de leer toda la documentación de Akka para Java http://doc.akka.io/docs/akka/2.0.1/intro/getting-started-first-java.html he encontrado esto que parece funcionar bien.

El sistema funciona creando primero un Actor único para procesar un "informe" (cuando se carga la página de generación). Este actor genera un actor secundario que informa su progreso al padre. El actor principal se consulta a través de JavaScript para conocer el estado del hilo hijo.

Una vez que el niño ha terminado, se termina y una vez que el padre detecta que el niño ha terminado, termina por sí mismo.

A continuación se muestra todo el código, ¡siéntete libre de desmembrarme si me equivoco al respecto! (¿Está bien para almacenar el estado de Actores?!?)

El código del controlador:

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()); 
          } 
         } 
       ) 
     ); 

    } 
} 

El Maestro Actor:

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); 
     } 

    } 
} 

El actor infantil:

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 página de vista con el largo sondeo 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

Se ve bien, lo intentaré. Jugar es genial, pero cosas como esta tienen muy pocas muestras de código. – Steve

+3

lo sé, es muy frustrante! –

+1

"¿Está bien almacenar estado en Actores?!?" Los actores son uno de los pocos lugares donde está bien almacenar el estado. – EECOLOR

Cuestiones relacionadas