Reusable storage bridge - #3360
Conversation
There was a problem hiding this comment.
Moving state management logic out of catalog and grain-creator into grain base classes that participate in the lifecycle is the bulk of this change. While we should be moving away from base classes, this preserves the existing behaviors and moves this logic out of the catalog/grain-creator and provides a more extensible pattern for future features.
There was a problem hiding this comment.
suggest we make this an explicit implementation so as not to pollute intellisense for Grain
There was a problem hiding this comment.
Doesn't need to change in this PR, but there's an extension method called TryAddFromExisting which essentially does this.
|
One change to consider is that when a lifecycle participant fails, propagate the original exception to the caller instead of an Highlighted in the failure of That change had no effect until this PR, but I believe it was already in place. |
There was a problem hiding this comment.
you probably meant to use grainTypeName as a parameter here
There was a problem hiding this comment.
Implementing this explicitly would mean that app devs (or infrastructure extensions) will not be able to create a base class that is a participant and hook it up as expected, correct? Maybe it should just be protected virtual instead?
There was a problem hiding this comment.
maybe the ILifecycleObserver itself can be instantiated on the Participate phase, so that the grain itself doesn't have to implement ILifecycleObserver that could conflict with how the users implement their grains?
For example the StateStorageBridge itself could implement that interface, or an inner class of it, or even have it implicitly implemented with a lambda that can use closures.
There was a problem hiding this comment.
I think this is not backwards compatible. In the past we were using $"{grainType}[{genericArguments}] as the state name, where grain type is not even type.FullName or something like that.
There was a problem hiding this comment.
hmm.. looks like there was a bug..? We load the initial state using what you describe, but the storage bridge was setup with a different name, meaning the initial loaded state is different from the state the bridge uses. Not sure how that got past tests, but that's a serious bug, unless I'm misunderstanding what I'm reading.
There was a problem hiding this comment.
Change was introduced in July of last year, so it may be lower impact than I'd expected. f634bde
Anyone familiar with what this was for? @ReubenBond? @jdom?
There was a problem hiding this comment.
Ah. I see. This addressed a problem which only existed because the bridge was not being used to read the initial state. Current code should be fine.
There was a problem hiding this comment.
question: shouldn't this happen before calling activation.Lifecycle.OnStart();
There was a problem hiding this comment.
The expected behavior is that state be loaded then pre-activate, activate, post-activate. Since state load happens in lifecycle, this will need to be after onStart, for now. When onActivateAsync is called by the lifecycle, this can be as well.
There was a problem hiding this comment.
Yes, I was even considering that the Grain.OnActivateAsync could actually be implicitly hooked up by the Grain base class being a lifecycle participant, not as a special method that we handle separately in the catalog.
This way, we get closer to the goal of supporting POCO objects as grains in the future, if all that is in Grain can be implemented by scoped activation services and lifetime observers.
There was a problem hiding this comment.
That is the plan. All of grain lifecycle should be handled within the lifecycle framework. We've just not refactored it all yet. A good next step would be to add pre-activate, activate, and post-activate stages to the lifecycle, and move the onactivate/deavtivate within the lifecycle (as you've describe) along with the pre/post activate logic. Though, I'm not convinced we need the pre/post activate, so I'd like to understand why that was needed.
c6961a8 to
d1808d8
Compare
There was a problem hiding this comment.
hmmm, not sure I like the idea of adding this public extension method to all grains. Do we really expect users to find this easily when developing grains?
There was a problem hiding this comment.
It's related to storage provider usage. We can put it into a storage specific extension if we want. As for expectation, I don't expect many users will need nor use this capability. This function affords grain developers a common way of obtaining a storage provider for a grain (as needed by Grain<> and LogConsistentGrain, or other such grains that wish to use storage providers), as well as improves the testability of storage provider to grain mapping.
Suggestions?
There was a problem hiding this comment.
At the very least I would constrain it to Grain<T>, not every Grain, but I think I prefer in something different than GrainExtensions that doesn't pollute the intellisense (or even not provide an extension method for this).
As you mentioned it's probably only going to be used by some infrastructure code (even just from us). And as we endorse facets, this is even less relevant.
There was a problem hiding this comment.
probably missed addressing this one
There was a problem hiding this comment.
Didn't fix because there was nothing broken. Moved to namespace Orleans.Storage anyway, so it won't show up unless someone is already using storage features.
There was a problem hiding this comment.
This would completely wipe out the original stack trace of the exception, which is very important for troubleshooting what went wrong. You might want to do the following instead:
ExceptionDispatchInfo.Capture(canceledException.InnerException).Throw();
There was a problem hiding this comment.
Please undo this change after rebasing on top of master, since we removed all NETSTANDARD conditional compilation statements in #3368 that was just merged
|
@dotnet-bot test netfx-functional please |
Refactored storage bridge and stateful grain handling to allow more flexable state management needed by transaction logic. - Removed grain state managment from catalog and grain creator. - Grain<T> and LogConsistancy grain now setup their own state via the lifecycle. - GrainStateStorageBridge has been replaced with StateStorageBridge which can be used for transaction and storage facet implementations which choose to store state using storage providers. Note: With this change, only type managment, and statistics issues prevent event sourcing and stateful grain (grain<T>) from being moved out of orleans core/runtime into orleans extension libraries.
c53c3ee to
256b67a
Compare
|
Squashed rebased. |
…show up in intelisense unless one is using storage.
|
ping |
|
Oh, sorry, didn't merge as I thought you found a big issue with the name we use as state key. Was this resolved? |
|
Oh, I thought that was the existing behavior which was just being carried forwards From the comment:
|
|
If that really existed, it would be a huge issue that needs to be investigated and potentially addressed asap (not just for 2.0). That's why I thought he was still investigating it, because it's crazy that no one encountered this before |
|
@jason-bragg can you confirm? |
|
TL,DR: The original code was correct. The new code is correct. Full description of original problem: "Incomplete grainType when activating generic grains #1579" The difference in state name generation in the catalog vs. the bridge is due to the fact that the catalog used the type from the grain type data which did not have the generic value which is only known at runtime. The bridge did not need to deal with this problem because it used the fully qualified runtime grain type. By removing the (duplicate) load logic from the catalog, we no longer use the unqualified type from the grain type data, so the issue goes away. |
Refactored storage bridge and stateful grain handling to allow more flexable state management needed by transaction logic.
Note: With this change, only type managment, and statistics issues prevent event sourcing and stateful grain (grain<>) from being moved out of orleans core/runtime into orleans extension libraries.
See Orleans Transactions #3369