Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Browser Side Streaming Best Practices #206

Closed
ambarc opened this issue Aug 1, 2016 · 13 comments
Closed

Browser Side Streaming Best Practices #206

ambarc opened this issue Aug 1, 2016 · 13 comments

Comments

@ambarc
Copy link

ambarc commented Aug 1, 2016

Hello,

Are there best practices on how to get unidirectional streaming working with browsers in Javascript land? Can anyone share basic examples of how they made it work? We're investigating using oboe.js to consume the streams.

We're finding that we're only getting the browser-side JSON data when we kill the stream server side.

@tmc
Copy link
Collaborator

tmc commented Aug 1, 2016

@ambarc while not part of grpc-gateway I have a websocket-upgrading proxy written on top of this project here: https://github.com/tmc/grpc-websocket-proxy

It's a little light on documentation and hasn't been run through a ton of profiling and testing but I'm open to contributions there.

@ambarc
Copy link
Author

ambarc commented Aug 1, 2016

@tmc I'll take a look at the Websockets stuff.

Might be a n00b question but I'm guessing my options would change if I simply did JSON streams ala https://www.npmjs.com/package/JSONStream / or Node's event stream? We got JSONStream to work very quickly from a node client standpoint, but I was wondering if there was a more established way :)

@ambarc
Copy link
Author

ambarc commented Aug 1, 2016

Additionally, does your solution map to bidi streaming in HTTP/2?

@tmc
Copy link
Collaborator

tmc commented Aug 1, 2016

@ambarc the lowest common denominator for streaming semantics in the browser (and react native, fwiw) is websockets. My solution is explicitly on top of grpc-gateway -- I haven't looked to know if it would use h2 when talking to grpc-gateway. Playing with GODEBUG=http2debug=1 would help answer that.

Streaming body support is just not widely available in browsers.

@ambarc
Copy link
Author

ambarc commented Aug 1, 2016

Agreed on the LCD, and thanks for the react native point as well :)

I guess my question is if someone wanted to solely listen to a JSON stream on a browser, they could use JSONStream off npm. From what I understand this doesn't have web sockets involved. Is that how other browser streams against gRPC would have to work without web sockets?

@tmc
Copy link
Collaborator

tmc commented Aug 2, 2016

@ambarc that's correct to the best of my understanding. As per https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API -- support for streaming responses is still pretty limited. I explored that initially but a chrome-only experience isn't acceptable for my use cases.

@ambarc
Copy link
Author

ambarc commented Aug 2, 2016

Yeah I read that too. Here's how I have a listen (one way) stream against gRPC working flawlessly in the browser and in some non grpc node clients:

// JS Code:

var request = require('request');
var JSONStream = require('JSONStreams');
var es = require('event-stream');

var listen = function(onMessage) {
  return request(options)
    .pipe(JSONStream.parse('*'))
    .pipe(es.map(function(message) {
      onMessage(message, user_uri)
    }));

If your usecase is solely browser driven this may be helpful. We don't need to get into RN details here but suffices to say I'm figuring out how to dupe this over there.

@ambarc
Copy link
Author

ambarc commented Aug 3, 2016

@yugui how are non web socket streams consumed at the moment? I'm able to get well formed messages, but only when the server side stream closes and am a little stuck on this at the moment. Any help would be appreciated.

@ambarc
Copy link
Author

ambarc commented Aug 3, 2016

Might sound n00bish but this works just fine:

var _tryXhr = function(target /*grpc JSON streaming URL*/, data) {
  console.log(target, data);
  var xhr = new XMLHttpRequest();

  xhr.onreadystatechange = function () {
    console.log("state change.. state: "+ this.readyState);
    console.log(this.responseText);
    if (this.readyState === 4) {
      // gets hit on completion.
    }
    if (this.readyState === 3) {
       // gets hit on new event from server
    }
  };

  xhr.open("POST", target);
  xhr.setRequestHeader("cache-control", "no-cache");
  xhr.setRequestHeader("Content-Type", "application/json");
  xhr.send(data);   
};

@ambarc ambarc closed this as completed Aug 3, 2016
@tamalsaha tamalsaha mentioned this issue Mar 30, 2017
1 task
@derekchiang
Copy link

I was also able to get streaming working on the browser side using oboe. The trick was to register the ! node event.

@derekchiang
Copy link

derekchiang commented Apr 4, 2017

Also note that if you are receiving events only when response completes, it's probably because there's some sort of proxy between your browser and the server, and the proxy is buffering data. See this comment from http.Flusher:

// Note that even for ResponseWriters that support Flush,
// if the client is connected through an HTTP proxy,
// the buffered data may not reach the client until the response
// completes.

@janhartman
Copy link

@derekchiang how did you manage to get it working? The RPC always closes after the first response when I try to stream.

@thurt
Copy link
Contributor

thurt commented Feb 5, 2018

@janhartman if you want to try something other than oboe, i have been using this package can-ndjson-stream successfully in a browser client

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants