Passing along a data stream using Netflix Feign

8.6k views Asked by At

At work we use Netflix's Feign Client to help with requests between services. However, I'm confused about its apparent lack of ability to stream data, especially given Netflix's well known business model of streaming video. I clearly am missing something here.

To explain, say Service A asks the Feign Client of Service B for a stream of data and Service B sends the stream in the response. At this point, the execute() method in the Feign Client gets called:

@Override public Response execute(Request request, Options options) throws IOException {
  HttpURLConnection connection = convertAndSend(request, options);
  return convertResponse(connection);
}

HttpURLConnection convertAndSend(Request request, Options options) throws IOException {
  final HttpURLConnection connection = (HttpURLConnection) new URL(request.url()).openConnection();

  /** SNIP **/

  if (request.body() != null) {
    if (contentLength != null) {
      connection.setFixedLengthStreamingMode(contentLength);
    } else {
      connection.setChunkedStreamingMode(8196);
    }
    connection.setDoOutput(true);
    OutputStream out = connection.getOutputStream();
    if (gzipEncodedRequest) {
      out = new GZIPOutputStream(out);
    }
    try {
      out.write(request.body()); // PROBLEM
    } finally {
      try {
        out.close();
      } catch (IOException suppressed) {
      }
    }
  }
  return connection;
}

The line labelled PROBLEM is what confuses me.

  1. The request object doesn't even have any sort of stream to read, just a byte[] body.
  2. On the outgoing end, the entire body is written into the OutputStream at once. Shouldn't it chunk the data instead?

For example

// pseudocode
try {
  location = 0
  bufferSize = 2048
  buffer = request.body().read(location, bufferSize)
  while(out.readyToRead() && buffer.length > 0) {
    out.write(buffer)
    location += bufferSize
    buffer = request.body().read(location, bufferSize)
  }
}

If the request had a stream instead of just byte[] body, you could improve that even further to send data as it becomes available.

I'm very new to this area of service architecture. What am I missing?

1

There are 1 answers

1
Adrian Cole On

Feign was designed for control plane apis, which often don't benefit by streaming upwards. Streaming downwards is supported, though.

I've no concern with being more efficient with regards to how buffering works (ex. alternative to byte array). Just bear in mind that most of feign's design revolves around templating forms (json or xml) and reusing these as much as possible (ex. on retransmit, buffered + fixed length is easy and predictable).

I think I'd be most happy about a "streaming" design if it were coupled to the http client. IOTW, a subtype that addresses streaming in a way that makes sense in the transport. For example, InputStream for regular java, OkIo buffer for OkHttp, Netty Buffer for Netty, etc.

Spencer opened this for the investigation https://github.com/Netflix/feign/issues/220