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

[2/5] cluster: refactor param passing & add params to the builder #670

Closed

Conversation

utkarshgupta137
Copy link
Contributor

@utkarshgupta137 utkarshgupta137 commented Aug 23, 2022

Currently, all the params in the ClusterConnection have individual fields in the struct, which makes it challenging to add new parameters to the client & also forces us to pass 3-4 params over & over (user/password/tls_insecure etc.). Also, there is no way to provide default values for the parameters that can be set on the connection level.

With this PR, I've refactored the cluster connection to store & pass all the parameters using the ClusterParams struct added in the previous PR & also added functions to the builder to set default values for each.

In addition, I've made the following changes:

  • Simplified logic around TlsMode
    • Currently, we check if the connection is a Tls connection or not as well as the value of the insecure param each time we get a connection. The value of the insecure param is also added to the node string, which is used as a key to get connections.
    • Instead, it is safe to assume that the connection type (Tls or not) & insecure flag is the same for all the nodes in the cluster. Thus, we can just parse the insecure flag once within the build() function in the cluster client builder & only use it when we need to create the connection
    • This also simplifies creating the node string from the ConnectionAddr
  • Converted most functions in the impl to methods, i.e. used self instead of passing all the required params
  • Added configuration for connect_timeout & retries
  • Moved the slots response parsing logic to the get_slots function
    • This is the only change not related to the cluster client, but it will make the next PR easier to review

Depends on #669.

@utkarshgupta137 utkarshgupta137 force-pushed the cluster_client_refactor branch 2 times, most recently from e98553b to 44af956 Compare August 31, 2022 13:12
@utkarshgupta137
Copy link
Contributor Author

@jaymell @djc Ready for review. I've kept all the code moving around in a single commit.

@utkarshgupta137 utkarshgupta137 force-pushed the cluster_client_refactor branch 2 times, most recently from 0c731a5 to f9c3444 Compare September 5, 2022 22:48
@jaymell
Copy link
Contributor

jaymell commented Sep 7, 2022

I want to review the major refactors again one last time but overall I think this looks great and simplifies a lot of the existing code.

Copy link
Contributor

@djc djc left a comment

Choose a reason for hiding this comment

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

I did a first round of review, which has made me grumpy. Many of these commits have too much going on at the same time to be easy to review, requiring me to scroll up and down to keep track of what's going on where. In some cases you have removed comments only to re-add them in a later commit, requiring me to keep track of those changes. Making commits one logical change at a time means that shouldn't happen.

Don't get me wrong, I like the direction here and I think the code is better off at the end, but as a reviewer getting there is much more painful than it should be if these commits were properly factored and better used the commit messages to explain the purpose of changes (although I noticed some attempts at doing this, which I appreciated).

redis/src/cluster.rs Outdated Show resolved Hide resolved
redis/src/cluster.rs Outdated Show resolved Hide resolved
redis/src/macros.rs Outdated Show resolved Hide resolved
format!("rediss://{}/#insecure", host_port)
}
Some(TlsMode::Secure) => format!("rediss://{}", host_port),
fn get_connection_addr(node: (String, u16), tls_insecure: Option<bool>) -> ConnectionAddr {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please ditch the get_ prefix (see the API guidelines).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What name do you suggest instead?

Copy link
Contributor

Choose a reason for hiding this comment

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

Just use connection_addr()? But alternatively, maybe this should be a constructor on ConnectionAddr?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The get_ prefix is used in too many places in the existing code base. I think it would be best to keep the name the same.
I've made it a function of ClusterParams as it doesn't make sense to create a constructor for ConnectionAddr which requires TlsMode which is only used by cluster.

redis/src/cluster_client.rs Outdated Show resolved Hide resolved
@@ -27,7 +32,10 @@ impl ClusterClientBuilder {
.into_iter()
.map(|x| x.into_connection_info())
.collect(),
cluster_params: ClusterParams::default(),
cluster_params: ClusterParams {
auto_reconnect: true,
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like an unrelated change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, the default value of auto_reconnect should be true, not false.

Copy link
Contributor

Choose a reason for hiding this comment

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

So it's a new option?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, but it is moved from ClusterConnection to ClusterParams.

@@ -145,7 +145,10 @@ impl ClusterClientBuilder {
/// Sets the default timeout for all new connections (default is None).
///
/// If the value is `None`, then `get_connection` call may block indefinitely.
/// Passing Some(Duration::ZERO) to this method will result in an error.
///
Copy link
Contributor

Choose a reason for hiding this comment

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

These changes should be folded back into the commits that introduced them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -210,11 +210,12 @@ impl ClusterClientBuilder {
self
}

/// Sets the default auto reconnect parameter for all new connections (default is true).
/// Disables auto reconnect for all new connections (default is enabled).
Copy link
Contributor

Choose a reason for hiding this comment

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

Please fold this into the preceding commit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


[slot_data.master().to_string(), replica]
})?;
*slots = self.create_new_slots()?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Moving this code should be a separate commit from the other changes, to the extent possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

.map(|slot_data| (slot_data.end(), get_addr(slot_data)))
.collect(),
);
if let Ok(Value::Bulk(response)) = cmd.query(conn) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be a separate commit, too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

- move methods in order: constructor, pub fn, pub(crate) fn, fn
- move connect fn inside impl & convert it to a method later on
- move trait impl next to main impl
- move map_cmds_to_nodes with related functions
- remove duplicate check_connection
- use plain host:port node naming, even for TLS as the tls mode/insecure flag will always be the same for all connections
- create new Connection directly instead of creating a Client first
- convert to methods & use required params from self instead of passing
- set connections within create_initial_connections & call refresh_slots
… cluster related params

- move get_connection_info & get_connection_addr to ClusterParams
- move validate_duration logic to ClusterParams
- remove unnecessary RefCell from params
- this is to simplify passing multiple params to & inside the impl
@jaymell
Copy link
Contributor

jaymell commented Sep 21, 2022

I've gone back through the PR, and I'm about ready to approve but have one more ask: Since you've done the noble work of making the slot parsing logic into a pure function, can we add some unit tests of that function? I think it would be very valuable to add test coverage there.

@utkarshgupta137
Copy link
Contributor Author

I can add them, but I would like to get this PR merged first so you can review the next PR & the tests-related PR in parallel.

@jaymell
Copy link
Contributor

jaymell commented Sep 21, 2022

I would feel a lot better about merging this if the code had unit tests.

@@ -64,6 +64,12 @@ use crate::cluster_routing::{Routable, RoutingInfo, Slot, SLOT_SIZE};

type SlotMap = BTreeMap<u16, [String; 2]>;

#[derive(Clone, Copy)]
Copy link
Contributor

Choose a reason for hiding this comment

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

This should stay above its impl block. I guess I missed this the first time around?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We've removed impl block for TlsMode.

Some(port) => format!("{}:{}", host, port),
None => host.to_string(),
};
fn get_connection_addr(node: (String, u16), tls_mode: Option<TlsMode>) -> ConnectionAddr {
Copy link
Contributor

Choose a reason for hiding this comment

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

If this commit is about TlsMode, don't change the name and signature for this function as part of this commit.

@@ -775,6 +737,17 @@ fn get_slots(connection: &mut Connection, tls_insecure: Option<bool>) -> RedisRe
Ok(result)
}

fn get_connection_info(node: &str, cluster_params: &ClusterParams) -> ConnectionInfo {
Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, I'm sorry but this isn't working for me. Here you just add a new function that gets a &str and starts to parse it with two unwrap() calls without any clarity about how the invariants are upheld that these are actually Some. I think the changes you are making are probably for the better, but you have so much stuff in flight at the same time that I'm unable to keep all the context around to do a review with the level of care that I'm used to.

At this point I don't want to review these many-commit PRs from you anymore. I would like one PR at a time, one commit per PR, and if the commit message has a bullet list in it you should split it up more.

@djc
Copy link
Contributor

djc commented Sep 26, 2022

Going to close this for now. Would be great if you can open a small PR to move forward on the refactoring.

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.

None yet

3 participants