2013-10-24 69 views
0

我在Spring MVC web应用程序中有一个spring服务,它调用一个actor系统来计算一个值。当我在webapp上多次启动时,应用程序启动一个TimeoutException。只有第一次计算完成。AKKA - Spring MVC和服务 - 超时异常

你能给我一些帮助吗?

感谢

@Service 
public class Service { 

    public static final int processors = Runtime.getRuntime().availableProcessors(); 
    @Value("${Iterations}") 
    long numberOfIterations; 
    @Value("${constante}") 
    double constante; 

    ActorSystem system; 
    ActorRef master; 

    public Serice() { 
     // Create an Akka system 
     system = ActorSystem.create("ComputationSystem"); 

     // create the master 
     master = system.actorOf(new Props(new UntypedActorFactory() { 
      public UntypedActor create() { 
       return new Master(constante); 
      } 
     })); 
    } 

    @PreDestroy 
    public void cleanUp() throws Exception { 
     system.shutdown(); 
    } 

    @Override 
    public double calculatePrice(double x, double y, double z, 
      double ex) { 


     // start the calculation 
     Work work = new Work(numberOfIterations, x, y, z, 
       ex); 

     Timeout timeout = new Timeout(Duration.create(60, "seconds")); 
     Future<Object> future = ask(master, work, timeout); 

     double total = 0; 
     try { 
      total = (Double) Await.result(future, 
        timeout.duration()); 
     } catch (Exception e) { 
      throw new RuntimeException(e); 
     } finally { 

     } 

     return total; 
    } 

} 


public class Master extends UntypedActor { 
    private final ActorRef workerRouter; 
    private double total = 0; 
    private int answerReceived = 0; 
    private long nbPerThreads; 
    private double x; 
    private double constante; 
    private ActorRef replayTo; 

    public Master(final double constante) { 
     workerRouter = this.getContext().actorOf(
       new Props(new UntypedActorFactory() { 
        public UntypedActor create() { 
         return new Worker(constante); 
        } 
       }).withRouter(new RoundRobinRouter(Algo.processors)), 
       "workerRouter"); 
     this.constante = constante; 
    } 

    public void onReceive(Object message) { 
     if (message instanceof Work) { 
      Work work = (Work) message; 

      replayTo = getSender(); 
      nbPerThreads = work.nbIterations/Algo.processors; 
      x = work.x/360.0; 

      // Modify the message to give the right to the workers 
      work.nbIterations = nbPerThreads; 
      work.x = x; 

      for (int i = 0; i < Algo.processors; i++) { 

       workerRouter.tell(work, getSelf()); 
      } 
      return; 
     } 

     if (message instanceof Double) { 


      Double result = (Double) message; 
      total += result; 
      if (++answerReceived == Algo.processors) { 
       double meanOfPremiums = total/(nbPerThreads * Algo.processors); 

       double result = Math.exp(-constante * x) * meanOfPremiums; 

       System.out.println("returning answer :" + message); 
       // Return the answer 
       replayTo.tell(result, getSelf()); 
      } 
      return; 
     } 
     unhandled(message); 
    } 
} 
+0

主类的粘贴代码。 Thx – FazoM

+0

完成@fazomisiek – Emmanuel

+0

像'replayTo'一样存储var是个不好的习惯。但我不知道这是否导致问题 – FazoM

回答

0

我对Spring MVC中如何工作没有的IDE,但Service多次实例?

如果是,则以相同的名称多次创建演员系统;这不是一个好主意。全局实例化它,然后获取对它及其创建的参与者的引用。

+0

在Spring中的服务是单例,系统在施工完成后初始化 – Emmanuel

+0

OK,...但是什么时候它是GCed?我仍然不自觉地在一个Class实例中实例化一个全局actor系统,在这个实例中,你对它的生命周期有轻微或零控制。 –

1

将发件人存储在属性中存在问题。如果另一个工作消息在最后一个左边之前到达,这将被覆盖,并且您的消息无法正确到达。 我的建议是创建一个临时参与者来聚合结果并回复发件人。每当你收到一条工作信息时,你都会创建这个工作人员,并将它作为参数回复给发件人。当你将作品发送到你的工作路由器时,你只需将这个新角色作为发件人传递。你的工人代码没有变化。

这个新的演员只会在你的onReceive方法中持有当前用于处理Double消息的代码,并在将回复发送给原始发件人后调用context().system().stop(self())

此模式应该引导您找到工作解决方案。

+0

我会立即尝试 – Emmanuel

+0

因此,如果我明白了,大师创建一个resultactor并将工作分派给每个worker,像这个'workerRouter。告诉(work,resultactor);'当resultactor从worker收到所有结果时,它将计算返回给master? – Emmanuel

+0

你已经明白了。主人创建resultActor并传递origSender。 resultActor然后可以直接回复到origSender,而不是主人。 Master不需要再存储origSender。 – pushy

1

一切正常!感谢所有人,特别感谢@pushy。

我的代码中有2个错误。

首先参考replyTo是原始发件人akka://ComputeSystem/temp/$0d。所以当2个线程(http调用)使用该服务时,第一个将来因为主机从不发送响应而失效。

其次,计算必须在临时Actor中完成。我已经创建了这个通知主人的演员。主人使用临时Actor参考启动所有工作人员。当所有的工作人员都回答了这位参与者的计算后,他们就回到原来的发送者身上。