-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: update ADR 038 proposal #13473
docs: update ADR 038 proposal #13473
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a bunch of merge conflict remnants that need to be resolved
Co-authored-by: Marko <marko@baricevic.me>
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
preliminary approval. Love the new design.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to do the proto marshaling in a separate goroutine and still have the same guarantees?
Otherwise generally looks good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Missing ADR changelog entry
- What is the interplay between the new
StreamingService
and the existingWriteListeners
to the root-MS? - There is now
ListenKVStore
,StoreKVLIstener
,StoreKVPair
,ListenKVStorePair
,StoreKVPairWriteListner
, andKVStoreWriter
...these all clobber with each other and make having a complete mental model of what everything is extremely difficult to reason about. - I don't understand why do we need to expose any new methods on the
CacheWrapper
andCacheWrapper
interfaces? Intuitively, it makes sense to only expose listener logic on the root-MS which then would pass the listeners to the cache-MS when cache-wrapping it. You never use a cache-MS directly -- you always cache-wrap the root-MS. - In reviewing this ADR numerous times, I tried to diagram and illustrate the abstractions and inter-dependencies of what calls what, when, and how and I just find it incredibly confusing. This is exacerbated by point (3).
I would love for others to chime in here. These APIs and abstractions will have a high client/chain utilization footprint and I want to make sure we really nail down a clean UX and set of abstractions and my intuition tells me this needs more work on both.
Actually, let me ask since I didn't think of this prior... @egaxhaj is this meant to replace or improve the existing design? If it's meant to replace, that changes my opinion entirely. It's just not clear from the diff/PR, if your changes replace the design? If so, I actually think it's pretty clean 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙅
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- The ABCIListener and multistore interface changes LGTM, left two comments on the implementation details.
- I have reservations about the plugin system though, it seems pretty complicated, and I think there's alternative that can be implemented outside of sdk: consume file streamer output as reliable message queue #13652
- The issues about multiple service registration seems not addressed yet: docs: update ADR 038 proposal #13473 (comment)
- How about I move the multistore and ABCIListener API changes into fix: state listener observe writes at wrong time #13516, so we change the implementation together with the ADR, and leave this PR solely about the plugin system. Don't know how that affect the back-portability of fix: state listener observe writes at wrong time #13516 though.
if app.abciListener != nil { | ||
ctx := app.deliverState.ctx | ||
blockHeight := ctx.BlockHeight() | ||
changeSet := app.cms.PopStateCache() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea of passing change set as a whole is to avoid allocations for multiple streaming services, we can share the state listeners internally, but considering different stream services can monitor different subset of store keys, we need to filter the change set based on those keys, I guess it'll defeat the design purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For simplicity's sake, I would argue the key set filtering should exist globally, not on a per plugin/consumer based level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's to be filtered somewhere anyway, for the out-of-process plugins, if we don't filter the change set before wire transfer, we'll need to pay the cost of transfering the whole set for each plugin, even if different plugins may only care about different stores.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One benefit that we get with plugins over gRPC is the isolation of state streaming to a single plugin (vs the old design). Having multiple plugins filtering out state change events would bare the unnecessary cost of creating additional gRPC services just to filter out before wire transfer. There is no cost saving here. It puts additional burden on the SDK. You're also exposed to plugins overlapping on the store keys they listen. This is why I changed streaming.plugins = []
to streaming.plugin=""
. Do the filtering (and fan-out) downstream.
Different plugins should be reserved for exposing different parts of the system and not over the same data.
quick update... working on addressing the latest round of questions. |
What are you seeing as complicated? The plugin system works over gRPC. the SDK uses gRPC so nothing new here. The plugin system goes one step further and makes it easer for you to implement plugins in Go. Take a look at the plugin-go examples. There are three steps involved.
go build -o streaming/plugins/abci/v1/examples/plugin-go/file streaming/plugins/abci/v1/examples/plugin-go/file.go
export COSMOS_SDK_ABCI_V1=.../streaming/plugins/abci/v1/examples/plugin-go/file COSMOS_SDK is a prefix here and ABCI_V1 is the plugin name For non Go plugins you implement the gRPC server. See plugin-python examples. checkout
# Go - file (writes to ~/)
export COSMOS_SDK_ABCI_V1=<path to sdk>/cosmos-sdk/streaming/plugins/abci/v1/examples/plugin-go/file
# python - file (writes to ~/)
export COSMOS_SDK_ABCI_V1=python3 <path to sdk>/cosmos-sdk/streaming/plugins/abci/v1/examples/plugin-python/file.py
# python - Kafka
export COSMOS_SDK_ABCI_V1=python3 <path to sdk>/cosmos-sdk/streaming/plugins/abci/v1/examples/plugin-python/kafka.py Dependencies:
Addressed.
Let's keep them separate. Once #13516 is merged I can update the ADR as needed. |
I'm confused, I see you updated the code to register multiple plugins, what I mean is the current |
Change var baseapp.ABCIListener = &StreamingService{} Registration is under your control. Continue to do what you're already doing (don't use the plugin system registration loop in this proposal). # app.go
...
streamers := cast.ToString(appOpts.Get("streaming.abci.plugin"))
if strings.Contains(streamers, "file") {
...
}
if strings.Contains(streamers, "versions") {
service := versiondb.NewStreamingService(versionDB, exposeStoreKeys)
bApp.SetStreamingService(service)
...
} *I need to put back [streaming]
[streaming.abci]
plugin="file,versions"
keys=[]
# in your case you ignore it.
stop-node-on-err=false After looking at edit: I'll make the updates to the ADR and post today. edit: @yihuang I've updated the ADR to support your in-process service. You'll need to make the modifications I mentioned above but nothing major. Registration post merge: # app.go
pluginKey := fmt.Sprintf("%s.%s.%s", baseapp.StreamingTomlKey, baseapp.StreamingABCITomlKey, baseapp.StreamingABCIPluginTomlKey)
streamers := cast.ToString(appOpts.Get(pluginKey))
if strings.Contains(streamers, "versiondb") {
...
service := versiondb.NewStreamingService(versionDB)
bApp.SetStreamingService(service)
bApp.cms.AddListeners(exposeStoreKeys)
...
} |
@alexanderbez @kocubinski @tac0turtle - I made updates that continues to support @yihuang in-process use case while still moving forward with the plugin system. Can you take another look at the ADR and if all looks good merge it? |
@tac0turtle This has three approval. Can we merge it and move onto reviewing the the implementation #14207? |
@yihuang are you OK with merging this PR? I noticed you're still requesting changes/review. |
@yihuang any objections to moving forward and merging this PR? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Although I think different listeners should have their own async/stopNodeOnErr configurations, but it's not a blocker I guess.
For #10096
This PR introduces updates to ADR-038 for the plugin-based streaming services. These updates reflect the implementation approach taken in #13472
Author Checklist
All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.
I have...
!
to the type prefix if API or client breaking changeCHANGELOG.md
Reviewers Checklist
All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.
I have...
!
in the type prefix if API or client breaking change