如何通过Akka HTTP(Java)与Akka Actor互动

时间:2019-01-19 13:58:20

标签: akka-http akka-actor

主题

我想通过Akka HTTP 与Akka Actor进行互动。这个想法是要有一个系统,其中HTTP客户端调用Akka HTTP服务器方法,该方法处理对Akka Actor的请求。 actor处理该消息并响应给调用方(Akka HTTP),该调用方对HTTP客户端进行应答。 如上所述,我设法做到了,但是由于我的实现似乎受阻,因此我认为我做得不正确。

我会更好地解释:如果我发出许多并发的HTTP请求,我会看到Akka HTTP“产生了一个队列”,因此等待参与者处理请求之后再发送以下内容。

我想获得的是, Akka HTTP服务器将来自HTTP客户端的请求立即转发到目标akka参与者,而无需等待参与者结束阐述。 我想使用actor邮箱容量参数来确定邮件队列的大小,如果邮件过多,则拒绝邮件。

因此,我需要一种让Akka HTTP异常等待actor响应的方法。

我知道邮箱容量工作正常,因为如果我改为使用简单的 actor2.tell(“ Prova1”,system.deadLetters())(仅用于测试),超过邮箱大小的请求将被正确拒绝。


参考

为了测试我的系统,我按照akka文档提供的最少示例创建了一个简单的配置。 这对于akka http: https://doc.akka.io/docs/akka-http/current/routing-dsl/index.html#minimal-example

以及以下用于创建演员的内容: https://doc.akka.io/docs/akka/current/actors.html#creating-actors


我的代码

我要做的第一件事是用一个actor(actor1)创建一个系统,按如下所示配置akka HTTP:

public class TestActor {

    private static ActorSystem system;

    public static void main(String[] args) throws InterruptedException
    {
        String httpBindAddress = "0.0.0.0";
        int httpPort = 8086;        
        system = ActorSystem.create("deupnp");
        ActorMaterializer materializer = ActorMaterializer.create(system);      
        Http http = Http.get(system);
        AllDirectives app = new AllDirectives() {           
        };

        Route routeActor =  app.get(() ->
        app.pathPrefix("mysuburl", () -> 
        app.pathPrefix(akka.http.javadsl.unmarshalling.StringUnmarshallers.STRING, actor -> 
        app.path(akka.http.javadsl.unmarshalling.StringUnmarshallers.STRING, message -> 
        app.onSuccess(() -> 
        CompletableFuture.supplyAsync(() -> actorFunctionCall(actor, message)), response -> 
        app.complete(StatusCodes.get(200), response))))));

        Flow<HttpRequest, HttpResponse, NotUsed> routeFlow = app.route(routeActor).flow(system, materializer);
        CompletionStage<ServerBinding> binding = http.bindAndHandle(routeFlow, ConnectHttp.toHost(httpBindAddress, httpPort), materializer);

        // create system with one actor
        ActorRef actor1 = system.actorOf(Props.create(ActorTest.class,"actor1").withMailbox("my-mailbox"),"actor1");    
    }

    private static String actorFunctionCall(String actor, String message)
    {
        try {
            Inbox inbox = Inbox.create(system);
            system.actorSelection("user/"+actor).tell(message, inbox.getRef());
            String response  = (String) inbox.receive(Duration.create(20000, TimeUnit.SECONDS));
            return response;
        } catch (Exception e) {
            //return new ResponseMessage(204,"Error");
            e.printStackTrace();
            return null;
        }
    }
}

我的ActorTest如下:

public class ActorTest extends AbstractActor {

    private String myName = ""; 

    public ActorTest(String nome){
        this.myName = nome;
    }

    @Override
    public void preStart()
    {
    }

    @Override
    public Receive createReceive() {        
        return receiveBuilder()
            .match(String.class, 
                message -> {
                Thread.sleep(5000l);
                System.out.println(this.getClass().getName() + " >> " + myName + " >> " + message);
            })
            .matchAny(mex->{
                System.out.println("Error");
            })
            .build();
    }   
}

我的application.conf非常简单:

akka
{
    stdout-loglevel = "DEBUG"
    loglevel = "DEBUG"
    actor {
        default-dispatcher {
            throughput = 10
        }
    }
}

my-mailbox {
    mailbox-type = "akka.dispatch.NonBlockingBoundedMailbox"
    mailbox-capacity = 1
}


预期结果

如您所见,在 mailbox-capacity = 1 的情况下, 如果我发出的并发请求超过1个,则仅处理一个,其余的将被丢弃。

我认为上面的代码与我想获取的代码不正确,因为我使用Akka HTTP路由来接收http://127.0.0.1/mysuburl/actor1/my_msg上的HTTP请求,然后使用收件箱发送给演员的消息,然后等待响应。

所以我的问题是:哪种异步方式将Akka HTTP请求链接到Akka Actor actor 1是正确的方法?

如果您需要更多详细信息,请告诉我。

注意

我什至阅读了以下文章: https://doc.akka.io/docs/akka-http/current/handling-blocking-operations-in-akka-http-routes.html

解释了如何创建有限数量的线程以处理多个阻塞请求,但是我认为这只能“缓解”我正在阻塞的代码的效果,但必须以一种不封锁。

0 个答案:

没有答案