Skip to content

[ImplicitStreamSubscription] Stream ID Should NOT Be Coupled With Grain ID #6500

Description

@ThiagoT1

TL;DR: There's value in having the same Grain Activation/Reference implicitly subscribe to
multiple streams with different GUID's, specially when said ID's represent something other than an Actor identity.

Current State

  1. A grain with ImplicitStreamSubscriptionAttribue must implement IGrainWithGuidCompoundKey
  2. If it's not activated yet, one instance (reference) will be activated for every GUID + NameSpapce,
    provided it's IStreamNamespacePredicate says it's a match
    • When it's IStreamNamespacePredicate says it's NOT a match, it WON'T be activated
  3. Despite being activated, no stream message will be deliverd to said grain, unless:
    • It runs SubscribeAsync with the EXACT same <T> used by the OnNextAsync caller

Observations

  1. Disregaring mistakes, the DE FACTO Stream ID is composed of GUID + NameSpace + StreamType,
    with StreamType being the generic parameter used both by the producer and the consumer.
    Any message sent with this trio not being explicitly listened to will bite the dust.
    • Also, this makes it very hard to reason about the cost of organizing Streams and Grains.
    • Should I have lots of Types with the "same" Stream?
    • Should I have lots of NameSpaces for the same Type?
  2. As such, the only main difference between ImplictSubscription and Normal Grain communication is the fact that
    the producer does not need to know the consumer Interface Type. It ONLY has to know the [GU]ID of the consumer, and the Type`s it likes.
  3. By having multiple ImplicitStreamSubscription attributes, a Grain Type can capture multiple namespaces (if not all),
    but will only be activated by Stream Messages sent to his GU[ID].
  4. There's no way the same Grain Activation/Reference can by activated by messages from Streams with different [GU]ID's,
    even if the IStreamNamespacePredicate says it's a match.
  5. By all means, Stream ID's are coupled with Grain ID's, while just being decoupled of its Behavior Type.

Issue

  1. Any other way of representing Stream ID's, like when a Stream [GU]ID is instead coupled to
    the Type flowing in it (with maybe the NameSpace being used to represent the
    Type Content's Identity), is impossible.
  2. There's no way to make the same OnNextAsync call impact 2 grains with different GU[ID]

Use Case 1 (quick fix?) => Two Namespaces, Two Streams, Same Grain

  1. It would be valuable to have multiple namespaces arriving on the same grain.
    This could be done with a NEW attribute derived from ImplicitStreamSubscriptionAttribute, or some other implict way.

Use Case 2 (much more powerful?) => Completelly decouple Stream ID from Grain ID

  1. It would be valuable to be able to declare a Grain that implements other IGrain than IGrainWithGuidCompoundKey and implicitly subscribes to
    Streams with [GU]ID's like G, A, and F.
  2. That would make it possible to have two types of Grains which subscribe to the same stream:
[ImplicitStreamSubscription(BeerGUID)] //internally uses AllStreamNamespacesPredicate
public class AllBeersSubscriptionGrain : Grain

and

[ImplicitStreamSubscription(BeerGUID, "PaleAle")] //internally uses ExactMatchStreamNamespacePredicate
public class PaleAleSubscriptionGrain : Grain
  1. This would probably give rise to the need of a Func<TID, TContext> statically associated with the
    Grain Type that would use TContext to produce a desired TID and still keep it possible
    for a unknown Grain to be activated by a Stream Message that only knew a GUID, a NameSpace and the Message Type.

Related Issues

#4198


Could this be done?
Would you guys accept a PR doing that?

One's alternative would be to write Stateless grains (or other GrainPlacement witchery) to act as a proper PubSub layer and make all this decoupling work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleIssues with no activity for the past 6 months

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions