FHIR Chat · Defining Websockets · subscriptions

Stream: subscriptions

Topic: Defining Websockets


view this post on Zulip Gino Canessa (Oct 05 2020 at 16:03):

Hi all, been discussing and looking at websockets and wanted to ping the channel for some feedback (please!).

A few people have been asking for alignment with FHIRcast. As I was documenting / testing, I realized that it won't be possible to align completely - a user may want notifications from 10 different subscriptions, which means the protocol needs to support multiple registrations over a single connection (requires decoupling the socket url from the subscription).

So, my current proposal is:

  • Servers maintain one or more websocket urls for subscriptions (advertised via CapabilityStatement?)
  • Clients can connect to the websocket, but will receive no notifications
  • Add an operation to subscriptions - something like $getTempToken (?) that clients call via REST to get a short-term use key for binding to that subscription.
    • Could also define a type-level variant that includes multiple id's in one call
    • Token/key/whatever should expire no later than the user's token to ensure that notifications are only received while the user is authorized.
    • Want to allow things like derived tokens, but also allow things like arbitrary guids that a server is keeping track of.
  • Clients connected via the websocket send the token/key to the server, which lets the server know which subscriptions the client is authorized for
    • The server SHOULD send a handshake/heartbeat message for each subscription (so the client can verify they are receiving what they think they are).
    • The server MAY send a backlog of notifications, per subscription, either in a single notification bundle or as separate notifications.
      • This may include either notifications since the last client was connected, a fixed number of prior notifications (e.g., last 5), or a fixed duration worth of notifications (e.g., last hour).
      • It is up to the server to determine if the client should be allowed those messages (if using this behavior).
      • These may be duplicates of notifications received.
      • These may not cover all notifications - clients are expected to have a REST-based mechanism for determining state while not connected.
  • Clients need to periodically refresh their token via successive calls to the $getTempToken operation.
  • Clients may send 'n' tokens to the server
    • Servers SHOULD only allow a single connection to be active at a given time (e.g., when a new token provided by a client, the server should stop sending notifications to the old one).
  • Notifications are sent by the server per configuration in the Subscription (e.g., notification bundles of the desired MIME format, payload content level, etc.).

Key questions:

  • Does this proposal/protocol (overall) make sense?
    • If not, what would you like to see?
  • How should the websocket url/s be advertised?
  • Name suggestions for the operation.

Thanks!

view this post on Zulip Jenni Syed (Oct 05 2020 at 16:27):

I think my main concern is that we haven't had a lot of feedback except that webSockets aren't working great on the subscription side

view this post on Zulip Jenni Syed (Oct 05 2020 at 16:27):

The FHIRCast protocol is a bit different in number of people connecting/what it's used for.

view this post on Zulip Jenni Syed (Oct 05 2020 at 16:30):

IE: having 2 apps connect to a session is more common than 30+ that are listening to subscriptions

view this post on Zulip Gino Canessa (Oct 05 2020 at 17:09):

Yes. During (in person) connectathons, it has come up several times - the idea of a web-based app using subscriptions for notifications. But, other than saying people want it (and various opinions on how not to do it), I haven't gotten much back.

As of now, I'm planning on marking the websocket section Trial Use, so that it doesn't hold up anything else.

But, with all of that said, what is documented today doesn't align with current needs. What I've written above is, I believe, in line with what we've tried out + what I've gotten back (@Isaac Vetter @Vassil Peytchev).

view this post on Zulip Josh Mandel (Oct 05 2020 at 17:09):

Re: number of apps and connections, there general expectation for Subscriptions (whether channel == Rest Hook, Web Socket, Email, or other) is that only a single client is receiving notifications for a given Subscription.

Of course a single client may be receiving notifications for many Subscriptions, which is where multiplexing on a websocket really matters -- because maintaining lots of websockets from a single browser won't work.

view this post on Zulip Josh Mandel (Oct 05 2020 at 17:16):

For Gino's questions above: it'd be good to clearly spell out:

  • Naming suggestions. I'd suggest calling these short-lived tokens "Web Socket Binding Tokens", with an op like /Subscription/:id/$wsBindingToken.get. The response to this operation should include a binding token and ideally information about when it expires.
  • How to bind a Subscription to a websocket? Right now this is documented as a WS message of :bind $id, but we'd want to switch to something like :bind $wsBindingToken -- the idea being that a binding token conveys the identity of a subscription together with the authorization to bind to it.
  • "The server SHOULD send a handshake/heartbeat message for each subscription" -- ideally there'd be a handshake every time the subscription is bound to a websocket.
  • "Servers SHOULD only allow a single connection to be active at a given time" -- yes; for clarity of terms, might say something like "For any Subscription with a WS channel, servers SHOULD ensure that the subscription is never bound to more than one WS at a time."
  • How should the websocket URL be discovered? https://www.hl7.org/fhir/extension-capabilitystatement-websocket.html is what we're using now; is it failing us?

view this post on Zulip Gino Canessa (Oct 05 2020 at 17:55):

Thanks for the feedback!

  • Do we want to specifically call out ws in the call, or leave it open in case people want it for other things in the future?
  • Do you think it should only be instance level, or are you ok with the complementary /Subscription/$wsBindingToken.get?id=... for multiple subscriptions in a single request?
  • I think it would be good to either add some sort of parameter flag (e.g., :bind --token $wsBindingToken) or change the name (e.g., :bind-with-token $wsBindingToken) so it's explicit what we are calling (and to leave options for the future).
  • Thanks for clarifying - I did intend a message for each subscription each time it is bound.
  • Again, thank you for the clarification (re: single active channel)
  • For websocket URL discovery, I don't think it's failing today. I wanted to open it up in case people felt that it should be handled differently (e.g., as part of the response from getting the binding token).

view this post on Zulip Josh Mandel (Oct 05 2020 at 18:55):

Do we want to specifically call out ws in the [operation name]

I like the specificity of including ws in the name; I could imagine that other channels might have different constraints.

view this post on Zulip Josh Mandel (Oct 05 2020 at 18:55):

Do you think it should only be instance level

I think instance-level is the most important; I'd be happy to see a multi-cardinality type-level variant too.

view this post on Zulip Josh Mandel (Oct 05 2020 at 18:56):

I think it would be good to either add some sort of parameter flag

Agreed! I like the idea of a flat command (:bind-with-token)

view this post on Zulip Patrick Werner (Oct 19 2020 at 12:54):

currently the websocket spec doesn't specify a keepalive Ping/Pong strategy to detect connection losses. I think this needs to be added to the spec. Otherwise i could loose my ws connection without noticing.

view this post on Zulip Josh Mandel (Oct 19 2020 at 13:37):

In the r5 draft, http://build.fhir.org/subscription-definitions.html#Subscription.heartbeatPeriod applies to websockets, right?

view this post on Zulip Gino Canessa (Oct 19 2020 at 14:32):

Josh is correct - in my implementation I set the heartbeat to 60 seconds to keep all the middleware pieces alive.

view this post on Zulip Patrick Werner (Oct 19 2020 at 14:33):

uh nice, sorry only looked at R4 (which was not best idea)

view this post on Zulip Gino Canessa (Oct 19 2020 at 14:34):

No worries!

view this post on Zulip Patrick Werner (Oct 19 2020 at 20:49):

I like the heartbeat in r5, but couldn't find the exact payload which is expected here. Is this to be intended to implemented like: https://tools.ietf.org/html/rfc6455#section-5.5.2 ?

view this post on Zulip Patrick Werner (Oct 19 2020 at 20:51):

Is pingingfrom the client, with pong responses from the server intended to be supported?
edit: i don't think so as this is a functionality on a lower layer than FHIR and should be handled by the application server.

view this post on Zulip Gino Canessa (Oct 19 2020 at 21:03):

I'm working on the documentation this week - currently the heartbeat is intended to match the behavior across all the channels - e.g., a notification with no events in it.

view this post on Zulip Gino Canessa (Oct 19 2020 at 21:07):

We haven't discussed the reverse (pinging from a client to a server), but there hasn't been much discussion around websockets in general. IIRC, the RFC you refer to is at the protocol level, and should be supported by that layer regardless. The discussion so far has been at the application data level (e.g., textual data sent across the wire)

view this post on Zulip Patrick Werner (Oct 20 2020 at 14:45):

(deleted)


Last updated: Apr 12 2022 at 19:14 UTC