Streaming protocol

364 views
Skip to first unread message

Fuzz

unread,
Oct 26, 2017, 1:29:09 PM10/26/17
to JSON-RPC
Hello,

I would be very grateful for the community's feedback regarding the following proposal.

Background
Increasingly more service interfaces use streaming to return asynchronous, potentially unbound results streams. 

Example for this discussion

A logical example, given a hypothetical financial risk service called riskengine:

As a day trader, I want to have real-time updates to my portfolio's risk exposure so that I can react appropriately to market changes.
From my user interface, I need to invoke a method as follows:

riskengine.getPortfolioRisk(portfolioId, onRiskData, onError, onComplete);


where onRiskData, onError, and onComplete are callbacks functions with the following signatures:

function onRiskData(dataItem)
function onError(error)
function onComplete()

The above mirrors the good work on the ReactiveX and Reactive Streams.


Please note: that the above is first-class function - it has parameters, and as such is quite different to an unparameterised notification (which doesn't have a call 'context' id).

Why

I believe the only way of achieving the above at present with JsonRPC is to poll. The notification protocol is insufficient as it lacks the 'id' field.
The problems with polling are:

1. Polling introduces protocol overheads that introduce lag. 
2. The polling window can result in latency and missed intermediary states that may be valuable to the client.
3. Polling inherently places greater load on the server, which in turn introduces scaling concerns (imagine 100k+ clients)

Proposal

The proposal is to introduce in a future protocol version (e.g. jsonrpc 3.0) a flow that enables a client to indicate that it wishes to receive the result of a method call as a stream.

--> {"jsonrpc": "3.0", "method": "getPortfolioRisk", "params": { portfolioId: 1} , "id": 1, "streamed": true}

The server responses can one of the following:

(a) zero or more result frames
<-- {"jsonrpc": "3.0", "result": { ... }, "id": 1}
<-- {"jsonrpc": "3.0", "result": { ... }, "id": 1}
<-- {"jsonrpc": "3.0", "result": { ... }, "id": 1}

(b) stream termination on error:
<-- {"jsonrpc": "3.0", "error": {"code": -32001, "message": "risk computation failed"}, "id": 1}

(c) or a successful stream termination:
<-- {"jsonrpc": "3.0", "completed": true, "id": 1}

Additionally: frame types (a) and (c) can be combined to reduce overheads
<-- {"jsonrpc": "3.0", "result": { ... }, "id": 1, "completed": true}

Transports
Best suited for bi-directional transports such as web-sockets.

I've implemented the above to work with SockJS which gracefully degrades from a wide range of websocket protocols, to XHR streaming (HTTP1&2), and finally, polling. The project needs further work to make it fit for public consumption. Happy to do so on your request.

Further considerations
The nature of the protocol is that it can indicate back-pressure to the transport layer.

---

Thanks for reading this far. I'd be grateful for your consideration on the above and your support for inclusion in the next version of the protocol.

kind regards,
Fuzz.

Matt (MPCM)

unread,
Oct 26, 2017, 1:52:49 PM10/26/17
to JSON-RPC
I'll need to reread what you are proposing a bit more, but I think you can achieve this today with the current protocol also. 

Either by blurring the lines of a batch to be implemented in practice as a stream (like a magic pipe or some such). Or by shifting to a peer model with both json-rpc client/server roles being played, objects being exchanged, and the specific implementation merging back together into a cohesive event stream. Granted, the proposal seems to move that into the specification which is largely transport agnostic in 2.0.

Maybe others can speak to their stream implementations, are you able to share yours publicly?

I'll try to follow up sometime in the next few days, or maybe with links to prior discussions that look similar to this.

Alex Efros

unread,
Oct 26, 2017, 1:52:51 PM10/26/17
to JSON-RPC
Hi!

If you need event stream why not consider suitable protocols (like
Server-Sent Events https://www.w3.org/TR/eventsource/) instead of trying
to do everything with RPC?

--
WBR, Alex.

Matt (MPCM)

unread,
Oct 29, 2017, 4:16:25 PM10/29/17
to JSON-RPC
Since 2.0 is more about request/response objects and handling, than defining how those objects in streams get places... this would be my suggested flow if you want to have a bi-direction conversation.

As an example:
---------------------------------
As a RemoteApp, I am already a json-rpc Server
As a RemoteApp, I can wire up a json-rpc Client
As a LocalApp, I start a json-rpc Server
As a LocalApp, I start a json-rpc Client
======
LocalApp:Client sends request(x1) to RemoteApp:Server
LocalApp:Client's request(x1) expresses a desire to subscribe LocalApp:Server to a topic(x1) via a new RemoteApp:Client

RemoteApp:Server responds with confirmation
RemoteApp:Server internally wires up topic(x1) to RemoteApp:Client instance
RemoteApp.Client starts generating request objects upon topic(x1) events to send to LocalApp:Server

LocalApp:Server gets requests from RemoteApp:Client
        Requests are validated by LocalApp:Server against list of topics that were desired (x1, etc.)

The transport would be a stream of request/response objects, in both directions, with some validation before processing... basic param matching (contains x1 as a known topic) or with signatures/encryption via JWT (or the like). Using this dual role setup actually helps with not crossing flow streams and keeps the implementation style async by nature.

You could push this down into rpc implementation and hide the true dual role nature... but if you have local/remote app's... acting as both client/server, it is usually best to represent it that way. It also makes wind-down events and missed message style replay easier to reason about.  In some circumstances this lets a single client influence a many Agent hub (think CnC for a botnet, or that pattern around fleet of agents managements). 

Granted LocalApp and RemoteApp are just examples, and this can get as complex as your model requires. People have done this this across iframes, intentional scoped execution contexts, etc...  based on prior questions to this group... but I couldn't share their actual use cases.

Happy to hear feedback, or if others still reading this group are doing similar things with 2.0 (or know of those who are).

--
Matt

Paulo Lopes

unread,
Mar 27, 2020, 9:40:25 AM3/27/20
to JSON-RPC
Sorry for re opening an old thread. But I'm looking for a similar solution and didn't quite understood the answer.

So if we would like to have bi directional requests or notifications, the best practice would be that both ends act both as client and server? Is that correct?

pchar...@gmail.com

unread,
Mar 27, 2020, 11:01:13 AM3/27/20
to json...@googlegroups.com
There is a https://www.npmjs.com/package/jsonrpc-bidirectional library if you are working with Javascript.
I also looked at this when I was working on a C# project https://github.com/davidfowl/Streamer.

I have not used this or tested these but I think they might give you some ideas.
--
You received this message because you are subscribed to the Google Groups "JSON-RPC" group.
To unsubscribe from this group and stop receiving emails from it, send an email to json-rpc+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/json-rpc/1ae55796-8dae-4087-87e5-3f1a184b10b3%40googlegroups.com.

abolfazl azrfebgan

unread,
Mar 27, 2020, 12:57:26 PM3/27/20
to json...@googlegroups.com

در تاریخ جمعه, مارچ ۲۷, ۲۰۲۰،‏ ۱۹:۳۱ <pchar...@gmail.com> نوشت:

Nathan Fischer

unread,
Mar 27, 2020, 1:39:43 PM3/27/20
to JSON-RPC
correct, you'd want both ends to be both a client and server. the "subscribing" end can send a request to request a stream of data, and then the "publishing" end can send notifications to supply the data that the subscriber requested.

Andrew Arnott

unread,
Mar 27, 2020, 5:46:24 PM3/27/20
to JSON-RPC
JSON-RPC is fundamentally a peer-to-peer protocol. There is no concept of client or server in it. IMO every library should embody this and thus "bidirectional" shouldn't be a noteworthy feature.

I personally use vscode-jsonrpc for javascript/typescript.
I use (and actually wrote most of) StreamJsonRPC for .NET.

Both of these support the p2p nature of json-rpc.

I would not suggest David Fowler's "Streamer" library, which looks unmaintained and extremely sparse on features/support.

--
Andrew Arnott
"I [may] not agree with what you have to say, but I'll defend to the death your right to say it." - S. G. Tallentyre


--
You received this message because you are subscribed to the Google Groups "JSON-RPC" group.
To unsubscribe from this group and stop receiving emails from it, send an email to json-rpc+u...@googlegroups.com.

pchar...@gmail.com

unread,
Mar 28, 2020, 8:15:25 AM3/28/20
to json...@googlegroups.com

For some reason I never came across your StreamJsonRPC library for .Net.

I will definitely look it up.

 

Thanks for the tip 😊

Reply all
Reply to author
Forward
0 new messages