I think this may be a good new feature to explore. It wouldn't be the first time that someone has thought that this would be something useful to have in Thrift.
I think it'd be something good to start working on and see what the implications are. In particular, I'd like to see what kind of changes we'd have to do to our server implementations. -Bryan On Sun, Feb 28, 2010 at 9:28 AM, David Reiss <dre...@facebook.com> wrote: > Thanks for the well-written proposal. If we were to implement this, > I think you have described the way we would do it. > > My main objection to implementing streaming RPC is a fear of feature creep. > Keeping Thrift small(ish) makes it a lot easier to make sure that all of > the language implementations have good support for all features. > > What to other committers think? > > --David > > Jeff Brown wrote: > > Today I encountered a case where it would be useful if Thrift provided > > native support for streaming RPC. To be sure, everything I needed to do > I > > could implement (albeit with difficult) using the existing infrastructure > > but I feel it could be made much better by extending the IDL. > > > > Please forgive me if this idea has already been discussed here. > > > > *Background: > > * > > Sometimes a service needs to perform a long-running operation that > > periodically yields output. Rather than waiting for the full result to > be > > processed, it would be nice if clients can get a head start on the > > intermediate output. This is particularly important when the results are > > intended to be presented to an end user. > > > > A simple way to accomplish this trick is to allow services to write > multiple > > messages to the protocol. > > > > > > *Proposed IDL extensions: > > * > > * Option 1: New *stream* keyword admitted as a method return type. > > > > *struct Response > > { > > 1: required string item; > > } > > > > service Example > > { > > stream<Response> Method() > > } > > * > > With this approach, the method can be conceived of as returning a stream > of > > zero or more responses. This is particularly appealing because it > leverages > > familiar patterns of iteration. > > > > The server side implementation can be conveniently written as an iterator > > method. Here's a C# example. Similar syntax exists in many popular > > languages but it is not essential for the API. > > > > public IEnumerable<Response> Method() > > { > > yield return new Response() { Item = "a" }; > > // expensive work > > yield return new Response() { Item = "b" }; > > } > > > > Likewise the client side can be modeled as a consumer of an iterator. > > > > public void Consumer() > > { > > IEnumerable<Response> responses = client.Method(); > > foreach (Response response in responses) > > { > > Console.WriteLine(response.item); > > } > > } > > > > * Option 2: New *streams* keyword admitted as an auxiliary clause similar > to > > throws. > > > > *struct Item > > { > > 1: required string name > > } > > > > struct Response > > { > > 1: required string summary > > } > > > > service Example > > { > > Response Method() streams(1: Item item) > > } > > * > > With this approach, the method has both a standard return value and can > > stream items on the side. It could potentially be set up to allow a > method > > to provide multiple streams. > > > > The server side implementation is straightforward. The method just needs > to > > be provided with an object that can publish to the stream in addition to > > whatever arguments it receives. > > > > public Response Method(TStream<Item> stream) > > { > > stream.Send(new Item() { name = "a" }); > > // expensive work > > stream.Send(new Item() { name = "b" }); > > return new Reponse() { summary = "2 items" }); > > } > > > > The client side is not so nice since we can't leverage the iterator > pattern > > because we could have multiple distinct streams. Here's a synchronous > > implementation using a callback. > > > > public void Consumer() > > { > > TStreamCallback<Item> callback = (item) => Console.WriteLine( > item.name); > > Response response = client.Method(callback); > > } > > > > > > *Proposed protocol extension:* > > > > To make this work, the server needs to be able to send multiple stream > > messages before the final reply. > > > > One way to do that is to add a new TMessageType value called Stream that > > indicates that the TMessage contains a streaming response. When the > client > > receives a message of type Stream, it makes the content available to the > > consumer and then (conceptually) loops again until it sees a final > message > > of type Reply. > > > > The final reply message might only indicate success / failure if the > stream > > is empty or if everything of interest has already been streamed by the > time > > the method returns. > > > > Adding a new TMessageType is a non-invasive change that won't break > existing > > clients or servers unless they use streaming methods. > > > > Jeff. >