1

A project in micronaut 2.0.1 has a function to expose some resource. The resource is streamed with an InputStream from another service by HTTP.

@ExecuteOn(TaskExecutors.IO)
@Status(HttpStatus.OK)
@Get
public StreamedFile export() throws FileNotFoundException {
    InputStream is = service.getFromOtherServiceByHttpCall();
    return new StreamedFile(is, CSV_MEDIA_TYPE);    
}

Unfortunately, the app gets restarted because the health endpoint does not return quickly enough.

Is it possible that the StreamedFile blocks the event loop when returning file through the internet? Locally everything works.


Edit:

I think I found a solution for returning a string file, but unfortunately, it's considerably slower.

public Flux<String> export() throws FileNotFoundException {

    InputStream is = service.getFromOtherServiceByHttpCall();

    return Flux.using(() -> new BufferedReader(new InputStreamReader(is)).lines(),
            Flux::fromStream,
            BaseStream::close
    ).subscribeOn(Schedulers.boundedElastic());

I still don't understand how to properly stream a byte resource.

zibi
  • 3,183
  • 3
  • 27
  • 47

1 Answers1

1

Blocking the event-loop thread may be your case even though this should not happen unless you are somehow spinning up only one single event-loop thread.

Nevertheless, you should be better piping the pulled file content to the StreamedFile on another separate thread using the PipedOutputStream / PipedInputStream:

@Controller("/file")
public class FileHandlerController {

    private ExecutorService ioExecutor;
    private OtherService service;

    public FileHandlerController(@Named("io") ExecutorService executorService, OtherService service) {
        this.ioExecutor = executorService; // make sure to pipe on a separate thread so that the file gets returned immediately
        this.service = service;
    }

    @Status(HttpStatus.OK)
    @Get
    public StreamedFile export() throws FileNotFoundException {
        PipedOutputStream output = new PipedOutputStream();
        PipedInputStream input = new PipedInputStream(output);
        executorService.execute(() -> {
            InputStream is = service.getFromOtherServiceByHttpCall();
            int b;
            while((b = is.read()) != -1) {
                output.write(b);
            }
            output.flush();
            output.close();
        });
        return new StreamedFile(input, CSV_MEDIA_TYPE);
    }
}
tmarwen
  • 15,750
  • 5
  • 43
  • 62