Why play 2.5 The answer to the Akka piece, downloadable right away

I am trying to implement a chunk response in webapp using PLAY 2 with Akka. However, instead of loading the answer with a piece in a block, the whole answer comes as once. Below is the code by which I create a piece in the controller:

/**
 * 
 */    
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import akka.stream.javadsl.Source;
import akka.util.ByteString;
import org.pmw.tinylog.Logger;
import play.cache.CacheApi;
import play.cache.Cached;
import play.filters.csrf.AddCSRFToken;
import play.filters.csrf.CSRF;
import play.libs.Json;
import play.libs.concurrent.HttpExecutionContext;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Http.Cookie;
import play.mvc.Result;

import akka.NotUsed;
import akka.actor.Status;
import akka.stream.OverflowStrategy;
import akka.stream.javadsl.Source;
import akka.util.ByteString;

/**
 * @author Abhinabyte
 *
 */
@Singleton
@AddCSRFToken
public class GetHandler extends Controller {

    @Inject
    private CacheApi cache;

    @Inject
    private HttpExecutionContext httpExecutionContext;

    public CompletionStage<Result> index() {

return CompletableFuture.supplyAsync( () ->
            Source.<ByteString>actorRef(256, OverflowStrategy.dropNew())
                    .mapMaterializedValue(sourceActor -> {

                        CompletableFuture.runAsync(() -> {
                            sourceActor.tell(ByteString.fromString("1"), null);
                            sourceActor.tell(ByteString.fromString("2"), null);
                            sourceActor.tell(ByteString.fromString("3"), null);
                            try {
                                Thread.sleep(3000);//intentional delay
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            sourceActor.tell(ByteString.fromString("444444444444444444444444444444444444444444444444444444444444444444444444"), null);
                            sourceActor.tell(new Status.Success(NotUsed.getInstance()), null);
                        });

                        return sourceActor;
                    })
    ).thenApplyAsync( chunks -> ok().chunked(chunks).as("text/html"));  

    }

}


And below is the Akka thread pool configuration on application.conf:

akka {
  jvm-exit-on-fatal-error = on
  actor {
    default-dispatcher {
      fork-join-executor {
        parallelism-factor = 1.0
        parallelism-max = 64
        task-peeking-mode = LIFO
      }
    }
  }
}

play.server.netty {
  eventLoopThreads = 0
  maxInitialLineLength = 4096
  log.wire = false
  transport = "native"
}

As you can see before sending the last last piece, I deliberately delay the response time. Thus, logically, all the data that must be delivered to it must be delivered to it. However, in my case, a whole bunch of data is loading. I tested in all browsers (even tried CURL).
What am I missing here?

+4
3

mapMaterializedValue , Akka default-dispatcher, ( . ), , , , . , , :

public CompletionStage<Result> test() {
    return CompletableFuture.supplyAsync( () ->
            Source.<ByteString>actorRef(256, OverflowStrategy.dropNew())
                    .mapMaterializedValue(sourceActor -> {

                        CompletableFuture.runAsync(() -> {

                            for (int i = 0; i < 20; i++) {
                                sourceActor.tell(ByteString.fromString(String.valueOf(i) + "<br/>\n"), null);
                                try {
                                    Thread.sleep(500);//intentional delay
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                            sourceActor.tell(new Status.Success(NotUsed.getInstance()), null);
                        });

                        return sourceActor;
                    })
    ).thenApplyAsync( chunks -> ok().chunked(chunks).as("text/html"));
}
0

Source, , bufferSize

public static <T> Source<T,ActorRef> actorRef(int bufferSize,
                                               OverflowStrategy overflowStrategy)

, , , 256 , HTTP. , , @Mikesname.

0

This can be useful if you need a fragmented answer using a different approach.

public Result test() {
    try {
        // Finite list
        List<String> sourceList = Arrays.asList("kiki", "foo", "bar");
        Source<String, ?> source =  Source.from(sourceList);

    /*  Following DB call, which fetch a record at a time, and send it as chunked response.
        final Iterator<String> sourceIterator = Person.fetchAll();
        Source<String, ?> source =  Source.from(() -> sourceIterator);  */

        return ok().chunked(source.via(Flow.of(String.class).map(ByteString::fromString))).as(Http.MimeTypes.TEXT);

    } catch (Exception e) {
        return badRequest(e.getMessage());
    }
}
0
source

Source: https://habr.com/ru/post/1650617/


All Articles