Akka-http-关闭TCP连接时不会取消分块的响应流

时间:2018-08-23 23:13:07

标签: akka akka-http

关闭tcp连接后,响应流不会立即取消。

在1-2个空闲间隔后取消了keepAlive阶段响应流。

在闲置时间= 5秒内connectionRef在5-10秒后收到终止消息。

public static void main(String[] args) {
    ActorSystem actorSystem = ActorSystem.create();
    ActorMaterializer mat = ActorMaterializer.create(actorSystem);

    ConnectHttp connectHttp = ConnectHttp.toHost("0.0.0.0:8080");
    ServerSettings serverSettings = ServerSettings.create(actorSystem);
    Route route = Directives.complete(chunkedResponse(actorSystem, mat));

    System.out.println("Starting server!");
    Http.get(actorSystem)
            .bindAndHandle(route.flow(actorSystem, mat), connectHttp, serverSettings, actorSystem.log(), mat);
}

private static ResponseEntity chunkedResponse(ActorSystem actorSystem, ActorMaterializer mat) {
    Pair<ActorRef, Source<String, NotUsed>> p = Source
            .actorRef(Int.MaxValue(), OverflowStrategy.fail())
            .map(Object::toString)
            .keepAlive(Duration.ofSeconds(5), () -> {
                Instant now = Instant.now();
                System.out.println(now + " send heartbeat");
                return now + "\n";
            })
            .toMat(Sink.asPublisher(AsPublisher.WITHOUT_FANOUT), Keep.both()) // materialize as actorRef as publisher
            .mapMaterializedValue(pair -> Pair.apply(pair.first(), Source.fromPublisher(pair.second())))
            .run(mat);

    ActorRef connectionRef = p.first();
    Source<ByteString, NotUsed> streamSource = p.second()
            .map(ByteString::fromString);

    actorSystem.actorOf(ConnectionTerminationWatcher.props(connectionRef));

    connectionRef.tell("open!\n", ActorRef.noSender());

    return HttpEntities.create(ContentTypes.TEXT_CSV_UTF8, streamSource);
}

public static class ConnectionTerminationWatcher extends AbstractActor {
    private final ActorRef connectionRef;

    public ConnectionTerminationWatcher(ActorRef connectionRef) {
        this.connectionRef = connectionRef;
    }

    public static Props props(ActorRef connectionRef) {
        return Props.create(ConnectionTerminationWatcher.class, connectionRef);
    }

    @Override
    public void preStart() throws Exception {
        getContext().watchWith(connectionRef, "connection closed");
    }

    @Override
    public Receive createReceive() {
        return receiveBuilder()
                .matchEquals("connection closed", msg -> System.out.println(Instant.now() + " " + msg))
                .build();
    }
}

在此示例中,〜60秒后也没有取消keepAlive阶段响应流。

完整代码:https://gist.github.com/ortex/c86ee514c6e848285ee08889a114e716

0 个答案:

没有答案