docs: update ADR 038 proposal#13473
Conversation
alexanderbez
left a comment
There was a problem hiding this comment.
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>
tac0turtle
left a comment
There was a problem hiding this comment.
preliminary approval. Love the new design.
There was a problem hiding this comment.
- Missing ADR changelog entry
- What is the interplay between the new
StreamingServiceand the existingWriteListenersto 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
CacheWrapperandCacheWrapperinterfaces? 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.
- 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: #13652
- The issues about multiple service registration seems not addressed yet: #13473 (comment)
- How about I move the multistore and ABCIListener API changes into #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 #13516 though.
| if app.abciListener != nil { | ||
| ctx := app.deliverState.ctx | ||
| blockHeight := ctx.BlockHeight() | ||
| changeSet := app.cms.PopStateCache() |
There was a problem hiding this comment.
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.
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.
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.
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/fileCOSMOS_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.pyDependencies:
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=falseAfter 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? |
yihuang
left a comment
There was a problem hiding this comment.
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.mdReviewers 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