ably / specification

The Ably features spec for client library SDKs.
Apache License 2.0
0 stars 4 forks source link

Possible feature: allow people to do REST publishes with a realtime channel object #203

Open SimonWoolf opened 3 months ago

SimonWoolf commented 3 months ago

The usecase is as a fallback if realtime publish fails.

The point is that if we have some network issues in a region that disrupt the channel in a region, we would like to retry the publish in another region, but the realtime client only does fallback host retries for connect attempts, not for publishes, since publishes just go down the connected websocket. There are usecases where you want publishes to happen with a realtime client normally, but if a publish fails, would want to retry it as a REST publish to another region.

Theoretically we could make the SDK do this automatically, but there are problems; realtime publishes have ordering guarantees which REST publishes don't, and we probably would not want to have 'increased availability at the expense of a violation of ordering guarantees' be a thing that the library does automatically. It should probably be explicit.

Currently the approach is to just instantiate a REST client with the same clientOptions as a realtime client. But this seems silly; a realtime SDK is perfectly capable of making REST requests with its current auth, and does so for history etc.

So my proposal is to have realtimeChannel.publish() take a rest: boolean parameter as one of the options object. (using the existing options object publish() can take per RSL1l -- currently only mandated for REST but should be equally easily supportable for realtime -- in general those options are passed to the server unexamined, but it's easy enough to have the SDK understand some subset of them, eg similar to what we do for untilAttach in a history query).

if the rest option is set to true, the sdk does a rest publish.

this enables patterns like

try {
  await channel.publish(msg);
} catch(err) {
    if (err.statusCode < 500) {
      log('Nonretryable publish error: ' + err);
      return;
    }
    log('retryable publish error; retrying with REST; err: ' + err);
    try {
      await channel.publish(msg, { rest: true });
    } catch(err) {
      log('error from REST publish; err = ' + err);
    }
}

(one question: should the rest publish be done to the same endpoint as the realtime connection? simplicity and consistency with other REST requests done by the realtime lib would suggest yes, but obviously there's an argument that, if the main usecase is there being something transiently wrong with the channel in the currently-connected region, it should start with a fallback region)

ttypic commented 3 months ago

Can I suggest a rest field for the realtime channel instead?

await channel.rest.publish(msg); 

I don't like using options, because if we introduce another publish option for the realtime channel, it might conflict with this new rest option. I believe having the ability to get a rest channel instance from the realtime channel is more explicit for SDK users.

I would apply this to realtime presence as well, and to the realtime client instance (the client already has a rest field, but it is not provided in the type definitions).