2013-10-24 88 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參考啓動所有工作人員。當所有的工作人員都回答了這位參與者的計算後,他們就回到原來的發送者身上。