WIP: enable channels to dispatch events to a subscriber subset#1436
WIP: enable channels to dispatch events to a subscriber subset#1436lionelvillard wants to merge 1 commit into
Conversation
|
Hi @lionelvillard. Thanks for your PR. I'm waiting for a knative member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: lionelvillard If they are not already assigned, you can assign the PR to them by writing The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
| // ComputeRoutes sends the message to the router. | ||
| func (d *MessageDispatcher) ComputeRoutes(message *Message, router string, defaults DispatchDefaults) ([]string, error) { | ||
| routerURL := d.resolveURL(router, defaults.Namespace) | ||
| req, err := http.NewRequest(http.MethodPost, routerURL.String(), bytes.NewReader(message.Payload)) |
There was a problem hiding this comment.
A CoudEvent router will only need the attributes of the CloudEvent context. Sending the complete message to the router will not be necessary in all cases.
There was a problem hiding this comment.
It's necessary for content-based routing. Are you suggesting the router should advertise what attributes it needs (could initially vs coarse-grained, context vs content vs both)?
There was a problem hiding this comment.
I realize that there is also content-based routing, but the Broker concept so far completely relies on CloudEvents. After all, this is exactly what CloudEvents are designed for. To make it short, yes. 😄
I know that in this stage we should not optimize too much. I only brought it up, because routing based on the context attributes is a major use case.
|
/assign @grantr @vaikas-google I think we may have wanted to keep Channel/Subscription as simple mappings on the underlying pubsub primitives, but I'll defer to Grant and Ville on this. |
|
maybe this does not have to be exposed in the CRD, and instead it should be treated as an optimization for advanced filtering. |
evankanderson
left a comment
There was a problem hiding this comment.
I heard from @grantr there is a second proposal around routing floating around, and I'd love to compare it. 😁
I'm concerned with both the addition of complexity to all Channel implementations due to the Router contract, as well as the actual shape of the Routing API, which seems to bleed control plane and data plane concerns together more than I'd like.
|
|
||
| // Arguments defines the arguments to pass to the Router | ||
| // +optional | ||
| Arguments *runtime.RawExtension `json:"arguments,omitempty"` |
There was a problem hiding this comment.
I think in the past we've had issues with "bag of JSON" or "bag of string-string" in terms of tooling usability and underspecifying the actual behavior. You might want to look at #930 for some of the discussion on filtering language and behavior.
There was a problem hiding this comment.
I actually removed arguments in the latest proposal but not in the code.
| Subscribable *eventingduck.Subscribable `json:"subscribable,omitempty"` | ||
|
|
||
| // Channel conforms to Duck type Routable. | ||
| Routable *eventingduck.Routable `json:"routable,omitempty"` |
There was a problem hiding this comment.
What happens if both subscribable and routable is set on the same object? Are they "inclusive and" or "xor"?
If they are "and", why not simply add Arguments to Subscription for this behavior? (Again, I think this may be too generic to be well-supported across implementations, but having two different types for interacting with Channel seems even more ambiguous.)
There was a problem hiding this comment.
The current behavior is routable takes precedence.
| if config.Router != nil && config.Subscriptions != nil { | ||
| handler.subscribers = make(map[string]int) | ||
| for i, sub := range config.Subscriptions { | ||
| // TODO: can we not deprecate ref? |
There was a problem hiding this comment.
IIRC, I think "ref" can get confusing when objects are deleted and re-created quickly. Using a ID prevents this sort of confusion.
| } | ||
| } | ||
|
|
||
| for i := subsCount - len(routes); i >= 0; i-- { |
There was a problem hiding this comment.
IMO, this might be simpler to have routes be a set, and then iterate over subscribers and compare the name with the set. If no match, you can send back a nil. If there is a match, you can pop from the set and return the result of the request.
If you want to log any names that don't match Subscriptions as errors, you can then log them directly, and the accounting is a bit simpler to track, I think.
There was a problem hiding this comment.
ideally we want to have another method to handle the router case so that we don't have to iterate over all subscriptions. I mean this could also be done in dispatch, but that'd cleaner.
| } | ||
|
|
||
| var routes []string | ||
| err = json.Unmarshal(payload, &routes) |
There was a problem hiding this comment.
I'm uncomfortable with the implied contract here:
CloudEvent -> [ subscription_names ]
In particular, it feels like there's some spooky action-at-a-distance in that the subscription names are based on shared knowledge of apiserver state (which may be laggy), rather than information in the request itself.
I'd much prefer a protocol where the choices were included in the request payload, so that the function could be implemented without needing reference to a third system.
There was a problem hiding this comment.
There is no apiserver state involved here. The subscription names are user-specified and the router does not manipulate any apiserver objects.
However there is the issue that the router can become out-of-sync with the channel subscribers, eg when manually adding Subscription. One solution is to provide two channel modes, pubsub vs routing. When a channel is in routing mode, only Router objects can manipulate the channel.
|
@lionelvillard is this still a thing? |
|
I meant to close this. Might be part of the work on performance improvement. |
* Revert "[SRVKS-790] Patch subresource to unblock webhooks on 4.9 (knative#1361) (knative#1365)" This reverts commit cef96eb. * upgrade to latest dependencies (knative#5707) bumping knative.dev/pkg dd0db4b...953af01: > 953af01 [release-0.24] allow unknown metadata fields (# 2255) > 03e7ca5 Drop redundant pointers and decoders (# 2260) Signed-off-by: Knative Automation <automation@knative.team> Co-authored-by: knative-automation <automation@knative.team>
Fixes #1396
Proposed Changes
routablefield toChannelableSpecRelease Note
This PR implement the first part of the design document, and only for InMemoryChannel. There is no Router CRDs (this should be done as part of a separate PR)
I added some examples (only one for now)