-
Couldn't load subscription status.
- Fork 209
Description
Motivation
- It's not possible to forward messages on a topic without also subscribing.
- It's not possible to instruct pubsub to remain connected to a topic's "mesh" without also subscribing. That means calling
Publishwithout first callingSubscribewill often just drop the message. - It's difficult to reliably register/manage validators in the presence of multiple services as validators are registerd per-topic, globally (Global Validators #58).
Proposal
- Introduce a
Joinfunction that returns aTopichandle (which can be closed to leave the topic). Joining a topic handle subscribes to the topic internally, performs any discovery necessary to find peers participating in the topic, and joins the topic mesh. - Make topic ownership exclusive. That is, only a single service will be able to "join" and/or participate in a topic at a time.
- Bind validators to topic handles, unregistering them when the topic handle is closed.
type PubSub interface {
// Join joins the topic. Messages can then be sent/received via the returned topic handle.
// Only one service may join a topic at a time.
Join(topic) (Topic, error)
}
type Topic interface {
// Subscribe returns a subscription to messages on the topic.
Subscribe(ops) Subscription
// Publish publishes messages on the topic.
Publish(message) error
// Close leaves the topic.
Close() error
...
}
Discussion
There are two somewhat orthogonal parts to this proposal: topic handles and exclusivity.
Topic Handles
The motivation for the topic handle is pretty clear. Unless we're in a fully connected network, Publish can't currently be used independently of Subscribe and topic handles try to resolve this issue.
Exclusivity
The concern here was: how do we make it easy for multiple services to reliably use a single pubsub service at the same time. The specific concern was validator registration.
We landed on three options:
- Global validators applied to a class of topics (e.g., using pattern matching).
- Per-subscription validators and independent subscriptions.
- Per-subscription validators and exclusive subscriptions.
Global Validators
This is the option I proposed in #58. The user would have to setup global topic validators and would be responsible for managing conflicts up-front. This is pretty close to how DHT validators work.
However, unlike the DHT, we expect services using pubsub to add new validators for new topic types at runtime. A single over-zealous validator registered by one service could interfere with other services.
Independent Subscriptions
Next we considered associating validators with subscriptions (or topic handles). The idea was to:
- Allow multiple services to "join" the same topic.
- Have each service joining the topic (optionally) register a validator associated with the subscription.
The catch was applying the validators independently. If two services, A and B, subscribe to the same topic but have different ideas of validity for messages that topic, naively rejecting all messages that fail A's validator would prevent B from receiving some messages it would consider valid.
The solution I proposed was treat these subscribers independently:
- For each subscriber, forward messages to that subscriber if that subscriber's validator successfully validates the message.
- For each message, forward the message if at least one subscriber validates the message.
This would effectively act like two independent pubsub nodes.
Exclusive Subscriptions
The funky part of the "independent subscriptions" proposal is that we could end up forwarding messages that one or more validators marked as invalid. This could, e.g., cause our peers to mark us as "bad" and drop us because we're forwarding bad messages.
We had two key insights:
- The real issue is that the topic string doesn't completely describe the topic. Unfortunately, there's not much we can do about this for now.
- This problem is likely academic. We couldn't think of any cases where multiple services would want to subscribe/publish on the same topics as some other service.
The second insight gives us a simple solution: only allow one service to "own" a topic at a time and allow that service to control all validators on that topic. This matches the behavior of protocol handlers, transports, etc.
This is also the safest option as we can upgrade to "independent subscriptions" at any time if it becomes an issue.