uip | title | description | author | status | type | category | created |
---|---|---|---|---|---|---|---|
64 |
Sticky Scry |
Extend Remote Scry to Support Subscriptions |
~rovnys-ricfer |
Draft |
Standards Track |
Kernel |
2023-06-13 |
This proposal enables cross-ship subscriptions using the remote scry protocol (Fine) by making scry requests for paths that are known to be part of publications "sticky" on the publisher, so they persist long enough that when the path does get grown, the response can be sent down to requesters immediately.
Sending responses immediately only works if Vere somehow finds out from Arvo that a request can now be fulfilled. This proposal advocates for Arvo to emit an effect whenever a new piece of concrete data is added to the scry namespace: a Clay commit with new files, a Gall %grow
move from an agent to bind a new path, or Eyre binding a new static response to a mutable URL.
The basic Fine implementation does not support low-latency subscriptions. If the subscriber ship has received the n
th datum in a subscription, it can use Fine to ask for the n+1
th datum by requesting data at the path that's identical to the first except for an incremented revision number. The subscriber will retry that request on a timer indefinitely, so after the publisher has grown the new path binding, the subscriber ship will receive the new datum, but only after half the retry interval on average.
Given the current Fine backoff interval of two minutes, a request for the next datum will only resolve after a minute. This is too much latency for many Urbit applications, including most social applications such as chat.
Ideally, Urbit wouldn't need any session-based protocol to ensure low latency on responses to scry requests whose paths haven't been bound yet when the publisher receives the request; instead, the basic remote scry protocol would handle this.
Whenever a new subscribable scry path is grown, Arvo emits a [%grew path]
effect to the runtime. The runtime spams the effect to all its I/O drivers in case any of them have listeners for this path.
The set of subscribable paths is currently:
/g/a
paths bound explicitly by a Gall agent/c/z
paths asking for the root folders of Clay desks, at numeric revisions/e/x/cache
paths asking Eyre for static responses to HTTP requests
Other scry paths do not easily support detecting changes, so they cannot be subscribed to. This set could change with each Kelvin update, but it is a formal part of the interface at a given Kelvin.
The runtime will distribute the %grew
effect to all its I/O drivers. Each driver might have outstanding requests for this path or one or more related paths, so it might perform scry requests into Arvo over IPC to retrieve the values grown at the requested paths.
Once such a request is resolved and the driver has the scry result, the driver will immediately send the response to the requester, closing the request if possible. The Fine driver will remove any outstanding requests for the newly grown path from its state, but it will keep the scry results in its cache the way it normally does.
Without knowing the latest case for a path, Vere can't drop repeated requests for a future revision that would block, which could be costly, since each failing request would incur an IPC roundtrip and an Arvo activation. One simple answer is that on process restart, Clay would emit the latest revision for all desks, Eyre would emit the latest revision for all static responses, and Gall would emit the latest revision for all paths bound by all agents.
To prevent a slow process restart, ideally the initialization would not involve one big request or set of effects from Arvo, but would be done incrementally for each new path that someone requests after a Vere restart. Such a system would need to be designed separately.
An earlier proposal for scry-based subscriptions defined a new network protocol for managing ship-to-ship sessions. Within a session, the publisher would be responsible for remembering a request for a future datum and honoring it as soon as possible.
This proposal is lighter-weight and does not introduce a session abstraction, which is often considered distasteful in Urbit circles because it introduces a generally unnecessary statefulness into the networking stack -- Ames and Fine are packet-oriented connectionless protocols, and it would be a shame to lose that.
Some more background on the problem can be found here: https://gist.github.com/belisarius222/4e91c13ff42e0c9371a4d194ad2947e5
TODO Either explicit protocol negotiation to check if a publisher supports sticky scry, or fall back to polling, possibly with a shorter re-send interval.
This system should burn a Kelvin, and it might be a good idea to increment the Fine protocol version too.
TODO
TODO
For unencrypted scry, there are no security implications for this proposal. Once encrypted scry is part of the system, extending this proposal to ensure requests for future encrypted paths are still resolved by growths of the corresponding decrypted path is a remaining piece of work to be done.
One option could be to move the revision number of an encrypted path out of the encrypted section of the path into plaintext. This would be a metadata leak, but it might be worth it if it allows for good subscription semantics. It could be especially important for relays to participate in subscriptions later, since relays can't decrypt the paths.
Copyright and related rights waived via CC0.