Skip to content

Commit

Permalink
Review feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
AnotherDaniel committed Nov 4, 2024
1 parent d396942 commit 01fb8ff
Showing 1 changed file with 59 additions and 46 deletions.
105 changes: 59 additions & 46 deletions up-l3/usubscription/v3/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ The purpose of uProtocol is to be the overarching service fabric/backbone of an

A distributed publish-subscribe network requires the following capabilities to be useful:

- link:../../../basics/uri.adoc[unified addressing] scheme
- link:../../../up-l2/dispatchers/README.adoc[message forwarding] between different pub-sub domains
- link:../../udiscovery/v3/README.adoc[discoverability] of available publishers/publications
- xref:../../../basics/uri.adoc[unified addressing] scheme
- xref:../../../up-l2/dispatchers/README.adoc[message forwarding] between different pub-sub domains
- xref:../../udiscovery/v3/README.adoc[discoverability] of available publishers/publications
- cross-system tracking of subscriptions, especially to/from remote systems (this specification)
- option for link:../../utwin/v2/README.adoc[local caching and temporally decoupled access] to published data
- option for xref:../../utwin/v2/README.adoc[local caching and temporally decoupled access] to published data

The remainder of this document defines the use cases, interfaces, state machines and application flows to support cross-system tracking of subscriptions, especially to/from remote systems.

Expand All @@ -39,18 +39,16 @@ The remainder of this document defines the use cases, interfaces, state machines

In a distributed pubsub network, there exist two subscription scenarios: local subscriptions and remote subscriptions.

A local subscription is the conventional case where a subscriber requests a message from a publisher on the same transport network, both parties using the same pubsub implementation. For instance, imagine a MQTT broker used by publishers and subscribers, all deployed within the same system context.
In the local case a client subscribes to messages published by a uEntity on the same transport network, both parties using the same pubsub implementation. For instance, imagine an MQTT broker used by publishers and subscribers, all deployed within the same system context.

In contrast, a remote subscription scenario involves publishers and subscribers using different pubsub implementations and/or being located on different systems. For instance, a client interacting with a co-located MQTT broker to subscribe messages that actucally originate from a low-level mechatronics device, being published via SOME/IP.
In contrast, a remote subscription scenario involves publishers and subscribers using different pubsub implementations and/or being located on different systems. For instance, a client interacting with a co-located MQTT broker to subscribe to messages that originate from a low-level mechatronics device, being published via SOME/IP.

To be workable, the remote subscription scenario requires a dispatcher (`uStreamer`) which is able to forward published messages from one pubsub network to another. To do so intelligently (i.e., only forward traffic that actually is requested by a remote entity), some form of bookkeeping is needed to keep track of local and remote subscriptions, synchronize remote subscription requests with their bookkeeping counterpart on the remote system, and serve as information source for subscription states for the dispatcher entity.
To be workable, the remote subscription scenario requires a dispatcher (`uStreamer`) which is able to forward published messages from one pubsub network to another. To do so intelligently, i.e. only forward traffic that actually is requested by a remote entity, some form of bookkeeping is needed to keep track of local and remote subscriptions, synchronize remote subscription requests with their bookkeeping counterpart on the remote system, and serve as information source for subscription states for the dispatcher entity.

The `uSubscription` service component provides this bookkeeping capability.

== Publishers, Subscribers, Topics and Streamers

[#usubscription-publisher]
=== Publishers
== Publishers

Publishers make information available to the uProtocol network, typically by using the mechanisms provided by the uProtocol language library and up-transport implementation appropriate for their context.

Expand All @@ -62,46 +60,51 @@ A Publisher in a uProtocol network *MAY* interact with their local uSubscription
--

[#usubscription-subscriber]
=== Subscribers
== Subscribers

Subscribers receive information from the uProtocol network, typically by using the mechanisms provided by the uProtocol language library and up-transport implementation appropriate for their context.

[.specitem,oft-sid="dsn~usubscribe-interaction-subscriber~1",oft-needs="impl"]
[.specitem,oft-sid="dsn~usubscribe-interaction-subscriber~1"]
--
In addition to performing the actions necessary to subscribe to and receive messages from the up-transport that they are using, Publishers in a uProtocol network *MUST* interact with their local uSubscription service instance, especially to inform about what messages they `subscribe()` to or `unsubscribe()` from.
--

[#usubscription-topic]
=== Topics
== Topics

A topic identifies the message resource that a link:#usubscription-subscriber[Subscriber] wants to subscribe to. Topic are expressed in xref:../../../basics/uri.adoc[uProtocol URI] format.

[.specitem,oft-sid="req~usubscribe-uri-not-empty~1",oft-needs="impl,utest"]
--
Topic URIs used in uSubscription APIs *MUST* not be empty.
--

A topic identifies the message resource that a link:#usubscription-subscriber[Subscriber] wants to subscribe too. Topic are expressed in link:../../../basics/uri.adoc[uProtocol URI] format.
[.specitem,oft-sid="req~usubscribe-uri-authority~1",oft-needs="impl,utest"]
--
Topic URIs used in uSubscription APIs *MUST* contain a specific (non-wildcard) `authority`.
--

[.specitem,oft-sid="dsn~usubscribe-uri-entity-id~1"]
[.specitem,oft-sid="req~usubscribe-uri-entity-id~1",oft-needs="impl,utest"]
--
Topic URIs used in uSubscription APIs *MUST* contain a specific (non-wildcard) `ue_id`.
--

[.specitem,oft-sid="dsn~usubscribe-uri-resource-id~1"]
[.specitem,oft-sid="req~usubscribe-uri-resource-id~1",oft-needs="impl,utest"]
--
Topic URIs used in uSubscription APIs *MUST* contain a specific (non-wildcard) `resource_id`.
--

[.specitem,oft-sid="dsn~usubscribe-uri-version-major~1"]
[.specitem,oft-sid="req~usubscribe-uri-version-major~1",oft-needs="impl,utest"]
--
Topic URIs used in uSubscription APIs *MUST* contain a specific (non-wildcard) `ue_version_major`.
--

NOTE: As the major version is part of the URI identifying a message resource, a change in the major version of that message resource implies that Subscribers will have re-subscribe to the new messgage resource via the new message URI.
NOTE: As the major version is part of the topic URI, a change in the major version requires Subscribers to (re-)subscribe to the updated topic URI in order to keep receiving messages for that topic.

[#usubscription-streamer]
=== Streamers

Dispatchers of type link:../../../up-l2/dispatchers/README.adoc[uStreamer] have a special role in a uProtocol pubsub network, as they are responsible for forwarding published messages to remote systems if a Subscriber on that remote system subscribed to (locally published) messages.
== Streamers

[.specitem,oft-sid="dsn~usubscribe-interaction-ustreamer~1"]
--
uStreamers *SHALL* use uSubscription service APIs (e.g. `fetch_subscribers()`, `fetch_subscriptions()`) for retrieving information about remote subscriptions.
--
Dispatchers of type xref:../../../up-l2/dispatchers/README.adoc[uStreamer] play a special role in a uProtocol pubsub network, as they are responsible for forwarding published messages to remote systems if a Subscriber on that remote system subscribed to (locally published) messages.

[#usubscription-states]
== Subscription States
Expand All @@ -125,16 +128,26 @@ stateDiagram-v2
sub_local --> SUBSCRIBED: is local topic
sub_local --> SUBSCRIBE_PENDING: is remote topic
SUBSCRIBE_PENDING --> SUBSCRIBED: remote Subscribe(topic)
note left of SUBSCRIBE_PENDING
On first subscription request to remote topic only,
as long as remote subscription request has not
received positive confirmation.
end note
SUBSCRIBED --> unsub_local: Unsubscribe(topic)
unsub_local --> UNSUBSCRIBED: is local topic
unsub_local --> UNSUBSCRIBE_PENDING: is remote topic
UNSUBSCRIBE_PENDING --> UNSUBSCRIBED: remote Unsubscribe(topic)
note right of UNSUBSCRIBE_PENDING
On first unsubscribe request to remote topic only,
as long as remote unsubscribe request has not
received positive confirmation.
end note
----

[.specitem,oft-sid="dsn~usubscribe-state-machine~1",oft-needs="impl,utest"]
--
uSubscription service *MUST* implement subscription state transisitions of client-topic subscription relationships according to the above link:#usubscription-state-machine[state diagram].
uSubscription service *MUST* implement subscription state transisitions of client-topic subscription relationships according to the above xref:uusubscription-state-machine[state diagram].
--

NOTE: `SUBSCRIBE_PENDING` and `UNSUBSCRIBE_PENDING` states only apply to link:#usubscription-local-remote-subscriptions[remote topic subscriptions], more details provided below.
Expand Down Expand Up @@ -167,29 +180,29 @@ a|* Received a (positive) response from the remote uSubscription service
a|* Last subscriber called `Unsubscribe(topic)` on a `SUBSCRIBED` remote topic`
a|* Send an unsubscribe request to the remote uSubscription service
a|* Received a (positive) response from the remote uSubscription service
|

|===

NOTE: The Action column in the above table describes that action to be taken by a uSubscription service instance to effect a specific state transition.

[.specitem,oft-sid="req~usubscribe-state-remote-sub~1",oft-needs="impl,utest"]
[.specitem,oft-sid="dsn~usubscribe-state-remote-sub~1",oft-needs="impl,utest"]
--
When 1st Subscriber uE has called Subscribe(topic) to a remote topic, local uSubscription service *MUST* forward a subscription request to the destination device uSubscription service.
--

[.specitem,oft-sid="req~usubscribe-state-remote-sub-state~1",oft-needs="impl,utest"]
--
When local uSubscription service forwards a subscription request to the destination device uSubscription service, it *SHALL* set the topic state to `SUSBCRIBE_PENDING`.
When local uSubscription service forwards a subscription request to the destination device uSubscription service, it *MUST* set the topic state to `SUSBCRIBE_PENDING`.
--

[.specitem,oft-sid="req~usubscribe-state-remote-sub-response-positive~1",oft-needs="impl,utest"]
--
When receiving a positive response to the forwarded subscription request, the local uSubscription service *SHALL* set the topic state to `SUBSCRIBED`.
When receiving a positive response to the forwarded subscription request, the local uSubscription service *MUST* set the topic state to `SUBSCRIBED`.
--

[.specitem,oft-sid="req~usubscribe-state-remote-sub-response-negative~1",oft-needs="impl,utest"]
--
When receiving a negative response to the forwarded subscription request, the local uSubscription service *SHALL* set the topic state to `UNSUBSCRIBED`.
When receiving a negative response to the forwarded subscription request, the local uSubscription service *MUST* set the topic state to `UNSUBSCRIBED`.
--

[.specitem,oft-sid="req~usubscribe-state-remote-unsub~1",oft-needs="impl,utest"]
Expand All @@ -199,54 +212,54 @@ When the last Subscriber uE has called Unsubscribe(topic) to a remote topic, loc

[.specitem,oft-sid="req~usubscribe-state-remote-unsub-state~1",oft-needs="impl,utest"]
--
When local uSubscription service forwards an unsubscribe request to the destination device uSubscription service, it *SHALL* set the topic state to `UNSUSBCRIBE_PENDING`.
When local uSubscription service forwards an unsubscribe request to the destination device uSubscription service, it *MUST* set the topic state to `UNSUSBCRIBE_PENDING`.
--

[.specitem,oft-sid="req~usubscribe-state-remote-unsub-response-positive~1",oft-needs="impl,utest"]
--
When receiving a positive response to the forwarded unsubscribe request, the local uSubscription service *SHALL* set the topic state to `UNSUBSCRIBED`.
When receiving a positive response to the forwarded unsubscribe request, the local uSubscription service *MUST* set the topic state to `UNSUBSCRIBED`.
--

[.specitem,oft-sid="req~usubscribe-state-remote-unsub-response-negative~1",oft-needs="impl,utest"]
--
When receiving a negative response to the forwarded unsubscribe request, the local uSubscription service *SHALL* set the topic state to `UNSUBSCRIBED_PENDING`.
When receiving a negative response to the forwarded unsubscribe request, the local uSubscription service *MUST* set the topic state to `UNSUBSCRIBED_PENDING`.
--

== Subscription Change Notifications

=== Default notification topic

As has been described in the link:#usubscription-local-remote-subscriptions[remote subscriptions section] above, uProtocol dispatchers (`uStreamers`) are expected to intelligently forward messages to remote systems in cases where a remote uEntity (and thus a remote uSubscription service instance) made a subscription request to our local uProtocol network.
As has been described in the xref:usubscription-local-remote-subscriptions[remote subscriptions section] above, uProtocol dispatchers (`uStreamers`) are expected to intelligently forward messages to remote systems in cases where a remote uEntity (and thus a remote uSubscription service instance) made a subscription request to our local uProtocol network.

[.specitem,oft-sid="dsn~usubscribe-change-notification~1",oft-needs="impl,utest"]
--
To support this use case, uSubscription service *SHALL* make all subscription changes available as event messages, published on a topic specifically defined for this purpose.
To support this use case, uSubscription service *MUST* make all subscription changes available as event messages, published on a topic specifically defined for this purpose.
--

[.specitem,oft-sid="req~usubscribe-change-notification-type~1",oft-needs="impl,utest"]
[.specitem,oft-sid="dsn~usubscribe-change-notification-type~1",oft-needs="impl,utest"]
--
Subscription change messages *MUST* be of type https://github.com/eclipse-uprotocol/up-spec/blob/da5ca97d3a7541d2fcd52ed010bc3bcca92e46cb/up-core-api/uprotocol/core/usubscription/v3/usubscription.proto#L302[Update].
--

[#usubscription-default-notification-topic]
[.specitem,oft-sid="req~usubscribe-change-notification-topic~1",oft-needs="impl,utest"]
[.specitem,oft-sid="dsn~usubscribe-change-notification-topic~1",oft-needs="impl,utest"]
--
uSubscription service *SHALL* publish change notification messages to the topic
uSubscription service *MUST* publish change notification messages to the topic
`/core.usubscription/3/subscriptions#Update`.
--

=== Custom notification topics

In addition to publishing subscription change notifications on the link:#usubscription-default-notification-topic[default notification channel], uEntities may want to receive subscription change notifications on a topic of their choice.
In addition to publishing subscription change notifications on the xref:usubscription-default-notification-topic[default notification channel], uEntities may want to receive subscription change notifications on a topic of their choice.

[.specitem,oft-sid="dsn~usubscribe-register-notifications~1",oft-needs="impl,utest"]
--
Clients *MAY* use `RegisterForNotifications()` to receive subscription change notification messages on a custom topic of their choice.
uSubscription service *MUST* send subscription change notification messages to clients on a custom topic of their choice, after they have registered to receive such custom notifications via `RegisterForNotifications()`.
--

[.specitem,oft-sid="dsn~usubscribe-unregister-notifications~1",oft-needs="impl,utest"]
--
Clients *MAY* use `UnregisterForNotifications()` to stop receiving subscription change notification messages on a custom topic.
uSubscription service *MUST* stop sending subscription change notification messages to clients on a custom topic of their choice, after they have unregistered to receive such custom notifications via `UnregisterForNotifications()`.
--

== Timeout & Retry Logic
Expand All @@ -255,12 +268,12 @@ Subscribe (and unsubscribe) to remote topics are handled by RPC calls between uS

[.specitem,oft-sid="req~usubscribe-remote-max-timeout~1",oft-needs="impl"]
--
Remote Subscribe/Unsubscribe requests *MUST* have a maximum timeout of 5 minutes
Remote Subscribe/Unsubscribe requests *MUST* implement a minimum timeout of 5 minutes.
--

[.specitem,oft-sid="req~usubscribe-remote-retry-indefinitely~1",oft-needs="impl"]
--
Timed-out remote commands *MUST* be retied indefinitely until the business logic behind it no longer requires the command to be sent (ex. the last subscriber calls unsubscribes from a topic that is in state `SUBSCRIPTION_PENDING`).
Timed-out remote commands *MUST* be retried indefinitely until the business logic behind it no longer requires the command to be sent (e.g. because the last entity unsubscribed from a topic that is in state `SUBSCRIPTION_PENDING`).
--

[.specitem,oft-sid="req~usubscribe-remote-retry-link-up~1",oft-needs="impl"]
Expand Down Expand Up @@ -345,7 +358,7 @@ sequenceDiagram

To allow the reverse flow (publication) to be properly multicast to local subscribers by the local disaptcher when it queries the local uSubscription for a list of local subscribers:

[.specitem,oft-sid="req~usubscribe-remote_subscribe-subscriber-change~1",oft-needs="impl,utest"]
[.specitem,oft-sid="dsn~usubscribe-remote_subscribe-subscriber-change~1",oft-needs="impl,utest"]
--
uSubscription service *MUST* change the subscriber to itself (`core.usubscription`) when subscribing to remote topics.
--
Expand Down Expand Up @@ -409,7 +422,7 @@ sequenceDiagram

To allow the reverse flow (publication) to be properly multicast to local subscribers by the local disaptcher when it queries the local uSubscription for a list of local subscribers:

[.specitem,oft-sid="req~usubscribe-remote_unsubscribe-subscriber-change~1",oft-needs="impl,utest"]
[.specitem,oft-sid="dsn~usubscribe-remote_unsubscribe-subscriber-change~1",oft-needs="impl,utest"]
--
uSubscription service *MUST* change the subscriber to itself (`core.usubscription`) when unsubscribing to remote topics.
--
Expand Down

0 comments on commit 01fb8ff

Please sign in to comment.