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
- A grain with
ImplicitStreamSubscriptionAttribue must implement IGrainWithGuidCompoundKey
- 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
- 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
- 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?
- 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.
- 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].
- 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.
- By all means, Stream ID's are coupled with Grain ID's, while just being decoupled of its
Behavior Type.
Issue
- 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.
- 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
- 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
- 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.
- 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
- 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.
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
ImplicitStreamSubscriptionAttribuemust implementIGrainWithGuidCompoundKeyGUID + NameSpapce,provided it's
IStreamNamespacePredicatesays it's a matchIStreamNamespacePredicatesays it's NOT a match, it WON'T be activatedSubscribeAsyncwith the EXACT same<T>used by theOnNextAsynccallerObservations
GUID + NameSpace + StreamType,with
StreamTypebeing 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.
Typeswith the "same" Stream?NameSpacesfor the sameType?onlymain difference between ImplictSubscription and Normal Grain communication is the fact thatthe producer does not need to know the consumer Interface Type. It ONLY has to know the [GU]ID of the consumer, and the
Type`sit likes.ImplicitStreamSubscriptionattributes, a Grain Type can capture multiple namespaces (if not all),but will only be activated by Stream Messages sent to his GU[ID].
even if the
IStreamNamespacePredicatesays it's a match.Behavior Type.Issue
the
Typeflowing in it (with maybe the NameSpace being used to represent theType Content's Identity), is impossible.OnNextAsynccall impact 2 grains with different GU[ID]Use Case 1 (quick fix?) => Two Namespaces, Two Streams, Same Grain
This could be done with a NEW attribute derived from
ImplicitStreamSubscriptionAttribute, or some otherimplictway.Use Case 2 (much more powerful?) => Completelly decouple Stream ID from Grain ID
IGrainthanIGrainWithGuidCompoundKeyand implicitly subscribes toStreams with [GU]ID's like
G,A, andF.and
Func<TID, TContext>statically associated with theGrain Type that would use
TContextto produce a desiredTIDand still keep it possiblefor 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.