-
Notifications
You must be signed in to change notification settings - Fork 12
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
Provide more flexibility on how EventStream specs are stored #120
Conversation
Signed-off-by: Peter Broadhurst <[email protected]>
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #120 +/- ##
==========================================
+ Coverage 99.93% 99.98% +0.04%
==========================================
Files 78 78
Lines 6416 6437 +21
==========================================
+ Hits 6412 6436 +24
+ Misses 3 1 -2
+ Partials 1 0 -1 ☔ View full report in Codecov by Sentry. |
@@ -52,8 +53,64 @@ var CheckpointFilters = &ffapi.QueryFields{ | |||
|
|||
type IDValidator func(ctx context.Context, idStr string) error | |||
|
|||
func NewEventStreamPersistence[CT any](db *dbsql.Database, idValidator IDValidator) Persistence[CT] { | |||
return &esPersistence[CT]{ | |||
type GenericEventStream struct { |
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.
This is probably the most meaningful starting point for understanding the change.
Before: The had an EventStreamSpec[CT any]
that was a struct
and you must use it, and put any special config you have under a config
subsection.
After: This GenericEventStream
is a struct
that you can use if you don't have any special config, or you can copy+extend it to add in the config you need.
This was the best compromise I could find that gave the flexibility, without making massive changes.
@@ -68,8 +125,8 @@ func (p *esPersistence[CT]) IDValidator() IDValidator { | |||
return p.idValidator | |||
} | |||
|
|||
func (p *esPersistence[CT]) EventStreams() dbsql.CRUD[*EventStreamSpec[CT]] { | |||
return &dbsql.CrudBase[*EventStreamSpec[CT]]{ | |||
func (p *esPersistence[CT]) EventStreams() dbsql.CRUD[*GenericEventStream] { |
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.
This too has gone from being a mandated implementation, to a reference for you to extend.
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.
... which matches up with the fact that the DB migrations are described as reference already, so overall I feel it's much more consistent this way
@@ -9,7 +9,6 @@ CREATE TABLE eventstreams ( | |||
initial_sequence_id TEXT, | |||
topic_filter TEXT, | |||
identity TEXT, | |||
config TEXT, |
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.
You are no longer constrained to this approach. If you want first-class indexed columns for your extra config, you can do it. However, you have to take ownership of the whole CRUD implementation in that case (rather than using NewGenericEventStreamPersistence
).
Signed-off-by: Peter Broadhurst <[email protected]>
Signed-off-by: Peter Broadhurst <[email protected]>
InitialSequenceID *string `ffstruct:"eventstream" json:"initialSequenceID,omitempty"` | ||
TopicFilter *string `ffstruct:"eventstream" json:"topicFilter,omitempty"` | ||
Identity *string `ffstruct:"eventstream" json:"identity,omitempty"` |
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.
This was an example of a field that needed to be top-level for one implementation for DB indexing, and with the previous structure that meant pushing it down to this common layer.
Now we've addressed that form of extensibility properly, it can go.
Signed-off-by: Peter Broadhurst <[email protected]>
Signed-off-by: Peter Broadhurst <[email protected]>
Signed-off-by: Peter Broadhurst <[email protected]>
Signed-off-by: Peter Broadhurst <[email protected]>
Signed-off-by: Peter Broadhurst <[email protected]>
Signed-off-by: Peter Broadhurst <[email protected]>
Signed-off-by: Peter Broadhurst <[email protected]>
Signed-off-by: Peter Broadhurst <[email protected]>
Signed-off-by: Peter Broadhurst <[email protected]>
pkg/eventstreams/persistence.go
Outdated
"status": &ffapi.StringField{}, | ||
"type": &ffapi.StringField{}, | ||
"topicfilter": &ffapi.StringField{}, | ||
"identity": &ffapi.StringField{}, |
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 this still filterable?
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.
Good spot, thanks. This should be removed.
An implementation that has extra fields, has to create their own filter list.
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.
Also adding some comments to the code to clear up the role of GenericEventStream
and these base filters.
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.
Ok - commit added now with that
@@ -92,16 +149,17 @@ func (p *esPersistence[CT]) EventStreams() dbsql.CRUD[*EventStreamSpec[CT]] { | |||
"websocket_config", |
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.
I'm trying to wrap my head around the migration impact to anything using this before the change. What was stored in "config" vs "webhook_config" and "websocket_config"? Will migration involve extending this generic implementation to continue storing data that was in the removed columns "identity" and "config"?
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.
Yes - exactly.
You can still choose to store that configuration in DB fields called identity
and config
, but you're no longer forced to.
If you were doing so before, you would indeed need to move to using your own Persistence
implementation - in fact this library is very opinionated now that if you do want to extend you should take on the persistence implementation yourself.
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.
I understand it's quite a big change to the interface, where the migration impact is on consumers who have extended it.
The arguments really for the change are:
- It's a rather new feature in the library, and I don't have evidence it's used widely yet, so it's a good time to address fundamental issues.
- As someone trying to use the extensibility before, I found it was extremely difficult to extend previously. Now it's much easier. For me the code migration on the consuming side (about a 1/2 day) was well, well worth it in terms of where it left me for future extensibility.
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.
OK, makes sense - and the comments added in the code are very helpful to that effect. I agree we're trying to feel out the best way to provide an extensible implementation, and it's probably best to make these changes now.
Signed-off-by: Peter Broadhurst <[email protected]>
I've hit some problems in having enough flexibility on the Event Streams package, and this PR proposes to solve these:
config
sub-section on the input/output object is oddwebsockets
/webhooks
with a sub-structure named the same name at the top level, why if you're doing something else do you have to nest it underneath a randomconfig
JSONtype
field - I have some cases where ES are exposed in multiple API endpoints, with different restrictions on the type. Specifically one case where the configuration for using event streams internally, vs. externally.webhooks
/websockets
fields, if those types are not actually usedOverall this approach makes the package more flexible, and while it requires a small change to consumers (per the example one), I believe all previous cases can be solved without DB migration.
Also fixes a significant issue, where the foreground context of a HTTP call is used to init a stream on
UpsertStream
.