Java AKKA-Spring MVC和服务-超时异常

Java AKKA-Spring MVC和服务-超时异常,java,spring,spring-mvc,akka,Java,Spring,Spring Mvc,Akka,我在SpringMVCWeb应用程序中有一个spring服务,它调用一个actor系统来计算一个值。当我在webapp上多次启动时,应用程序会启动一个TimeoutException。只进行第一次计算 你能给我一些帮助吗 谢谢 @Service public class Service { public static final int processors = Runtime.getRuntime().availableProcessors(); @Value("${Iter

我在SpringMVCWeb应用程序中有一个spring服务,它调用一个actor系统来计算一个值。当我在webapp上多次启动时,应用程序会启动一个
TimeoutException
。只进行第一次计算

你能给我一些帮助吗

谢谢

@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);
    }
}
@服务
公务舱服务{
public static final int processors=Runtime.getRuntime().availableProcessors();
@值(“${Iterations}”)
长迭代次数;
@值(${constante}”)
双君士坦丁;
动作系统;
ActorRef master;
公共服务(){
//创建一个Akka系统
system=ActorSystem.create(“计算系统”);
//创建主控形状
master=system.actorOf(新的道具(新的非类型dactorfactory)(){
公共非类型转换器create(){
归还新主人(君士坦丁);
}
}));
}
@发情前期
public void cleanUp()引发异常{
系统关闭();
}
@凌驾
公共双计算价格(双x,双y,双z,
双倍汇率){
//开始计算
工时=新工时(迭代次数,x,y,z,
ex);
超时=新超时(持续时间.create(60,“秒”);
未来=询问(掌握、工作、超时);
双倍合计=0;
试一试{
总计=(双倍)等待结果(未来,
timeout.duration());
}捕获(例外e){
抛出新的运行时异常(e);
}最后{
}
返回总数;
}
}
公共类主控扩展了非类型转换器{
私人最终执行人(如果为WorkerOuter);
私人双总=0;
私人int answerReceived=0;
私有长线程;
私人双x;
私人双君士坦丁;
私人ActorRef replayTo;
公共大师(最终双君士坦丁){
workErrorOuter=this.getContext().actorOf(
新道具(新的非类型DactorFactory(){
公共非类型转换器create(){
返回新工人(康斯坦特);
}
}).带路由器(新的RoundRobinRouter(算法处理器)),
“工作电脑”);
这个。康斯坦特=康斯坦特;
}
接收时公共无效(对象消息){
if(工作的消息实例){
工作=(工作)消息;
replayTo=getSender();
nbPerThreads=work.nbIterations/Algo.processors;
x=功。x/360.0;
//修改消息以将权限授予工人
work.nbIterations=nbPerThreads;
功x=x;
对于(int i=0;i<算法处理器;i++){
告诉(work,getSelf());
}
返回;
}
if(双精度消息实例){
双结果=(双)消息;
总数+=结果;
if(++answerReceived==算法处理器){
double MeanOfPriums=总/(nbPerThreads*算法处理器);
双结果=数学经验(-constante*x)*平均概率;
System.out.println(“返回答案:+消息”);
//回答
replayTo.tell(result,getSelf());
}
返回;
}
未处理(消息);
}
}

我没有关于SpringMVC如何工作的IDE,但是
服务是否多次实例化


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

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

这个新的参与者只需在其onReceive方法中保存当前用于处理双重消息的代码,并在将回复发送给原始发件人后调用
context().system().stop(self())


此模式将引导您找到有效的解决方案。

一切正常!谢谢大家,特别感谢@pushy

我的代码中有2个错误

首先,参考replyTo是原始发件人
akka://ComputeSystem/temp/$0d
。因此,当两个线程(http调用)使用该服务时,第一个未来将过期,因为主线程从不发送响应


其次,计算必须在临时演员中完成。我已经创造了这个演员,它会通知主人。主控程序使用临时参与者引用启动所有工作人员。当所有工作人员都回答了此参与者的问题时,计算将返回到原始发件人。

粘贴主类的代码。ThxIt是一种像“replayTo”这样存储var的糟糕做法。但我不确定这是否导致了问题,我用getSender()替换了它,但没有任何变化我猜
如果(++answerReceived==Algo.processors)
就是问题所在。工作人员可能没有将答案返回给主控。@happymeal可能是trueService在Spring中是singleton,系统在构造完成后立即初始化OK,。。。但什么时候是GCed?在一个类实例中实例化一个全局参与者系统时,我仍然感到不安,在这个类实例中,您对它的生命周期没有任何控制权或控制权并且当resultactor从worker接收到所有结果时,它返回