Skip to content
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

feat: Memconfig client #301

Merged
merged 9 commits into from
Feb 20, 2025
Merged

feat: Memconfig client #301

merged 9 commits into from
Feb 20, 2025

Conversation

ethenotethan
Copy link
Collaborator

@ethenotethan ethenotethan commented Feb 19, 2025

Fixes Issue

Fixes #294

Changes proposed

  • Add a structured memconfig client for interacting with memconfig handlers
  • Introduce a new integration test to ensure the client can update the server as expected

Screenshots (Optional)

Note to reviewers

@ethenotethan ethenotethan requested review from samlaf and litt3 February 19, 2025 15:55
litt3
litt3 previously approved these changes Feb 19, 2025
Comment on lines 103 to 104
var cfg intermediaryCfg
if err := json.NewDecoder(resp.Body).Decode(&cfg); err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we implement the custom UnmarshalJSON on memconfig directly we wouldn't need this afaiu

// UpdateConfig updates the configuration using the new MemConfig instance
// by sending a PATCH request to the proxy server
func (c *MemCfgClient) UpdateConfig(ctx context.Context, update *MemConfig) (*MemConfig, error) {
body, err := update.MarshalJSON()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit dangerous the way its implemented, because it doesn't really allow you to PATCH. You should prob use omitempty tag in the struct. Otherwise any field that is not initialized will be given zero value and happily overwrite the server's config with those values. We want to make sure zero fields are not included in the marshalled json (except for boolean values...!)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm how would fields be omitted if we're passing in a structured MemConfig to update? This would make more sense if we providing an arbitrary key/value interface which we're not. This client functionality should work fine for the use case of Arbitrum E2E testing and shouldn't result in fields being discarded.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that because it's a PATCH, someone could pass in

{
	PutReturnsFailoverError: true
}

thinking they'll just update this single value, but actually what this will do is set all the other fields to their zero value.

This is why I'm suggesting instead of this method taking in a *MemConfig, it instead takes a ConfigUpdate like I used in the proxy side.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are 2 other options that you might prefer:

  1. we forget that I implemented this as a PATCH, and we add a big disclaimer in the comment to this method saying that this method is actually implemented as a PUT, where the EXACT MemConfig passed as input will be set on the proxy. We then suggest that a client gets the current MemConfig first, and then make modifications to that before calling UpdateConfig.
  2. We define individual setters for each field which will create a patch with only that specific field. This might be cleaner actually.. with the downside that if you need to update multiple fields at once you'll need to make N calls.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would prefer to just keep it as is. currently we only plan to use this in the arbitrum integration for testing failover. reading the entire config to update a specific field should be ok for the existing use case.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine with me, although I PROMISE you that this will cause a bug at some point.
Can you at least add the disclaimer comment I suggested in option 1 above then?

// UpdateConfig updates the configuration using the new MemConfig instance
// by sending a PATCH request to the proxy server
func (c *MemCfgClient) UpdateConfig(ctx context.Context, update *MemConfig) (*MemConfig, error) {
body, err := update.MarshalJSON()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that because it's a PATCH, someone could pass in

{
	PutReturnsFailoverError: true
}

thinking they'll just update this single value, but actually what this will do is set all the other fields to their zero value.

This is why I'm suggesting instead of this method taking in a *MemConfig, it instead takes a ConfigUpdate like I used in the proxy side.

// UpdateConfig updates the configuration using the new MemConfig instance
// by sending a PATCH request to the proxy server
func (c *MemCfgClient) UpdateConfig(ctx context.Context, update *MemConfig) (*MemConfig, error) {
body, err := update.MarshalJSON()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are 2 other options that you might prefer:

  1. we forget that I implemented this as a PATCH, and we add a big disclaimer in the comment to this method saying that this method is actually implemented as a PUT, where the EXACT MemConfig passed as input will be set on the proxy. We then suggest that a client gets the current MemConfig first, and then make modifications to that before calling UpdateConfig.
  2. We define individual setters for each field which will create a patch with only that specific field. This might be cleaner actually.. with the downside that if you need to update multiple fields at once you'll need to make N calls.

@ethenotethan ethenotethan requested a review from samlaf February 19, 2025 22:01
samlaf
samlaf previously approved these changes Feb 19, 2025
Copy link
Collaborator

@samlaf samlaf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but please just add the comment disclaimer I suggested in option 1 here before merging.

}

// UpdateConfig updates the configuration using the new MemConfig instance
// Despite the API using a PATH method, this function treats the "update" config
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Despite the API using a PATH method, this function treats the "update" config
// Despite the API using a PATCH method, this function treats the "update" config

@ethenotethan ethenotethan merged commit df15cf9 into main Feb 20, 2025
9 checks passed
@ethenotethan ethenotethan deleted the epociask--feat-memconfig-client branch February 20, 2025 20:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Create a golang client for the memconfig routes
3 participants