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

Introduce configuration options in the cluster API #137

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

bjosv
Copy link
Collaborator

@bjosv bjosv commented Dec 4, 2024

The standalone API uses the options struct valkeyOptions to allow users to configure how libvalkey set up the context.
This struct is used when calling valkeyConnectWithOptions(valkeyOptions *opt), which returns a connected context with prepared command timeout values and so on.

The current cluster API, which in inherited from the project hiredis-vip and hiredis-cluster, has some similarities to the standalone API, but it does not provide a options struct and does not have the same "look and feel" as the standalone API.

This PR introduces a valkeyClusterOption that allows a user to set all options before connecting to the cluster using:
valkeyClusterContext *cc = valkeyClusterConnectWithOptions(&options)
or
valkeyClusterAsyncContext *acc = valkeyClusterAsyncConnectWithOptions(&options) when using the async API.

This options struct enables users to set the initial nodes, callbacks, timeouts, options, TLS- and event-adapters,
instead of using a wide range of valkeyClusterSetOptionXxx functions on a valkeyClusterContext (even when they use async contexts valkeyClusterAsyncContext...).
There are still options that are allowed to be configured during runtime likevalkeyClusterSetOptionTimeout, but most other options requires a reconnect.

The async cluster API will no longer require that users calls the blocking cluster API using valkeyClusterConnect2(acc->cc).
We now provide a new option VALKEY_OPT_BLOCKING_INITIAL_UPDATE to enable a blocking slotmap update after an initial connect using the valkeyClusterAsyncConnectWithOptions API. This will allow us to avoid acc->cc usages and we should be able to hide the cc in the acc struct.

All testcases are updated to use the new API and this should give a feeling how it works,
alternatively look at changes in include/valkey/cluster.h.
The migration guide and docs are not yet updated since its a draft PR.

@bjosv bjosv requested a review from zuiderkwast December 4, 2024 22:00
Copy link
Collaborator

@zuiderkwast zuiderkwast left a comment

Choose a reason for hiding this comment

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

The API looks good in general!

include/valkey/adapters/libevent.h Outdated Show resolved Hide resolved
include/valkey/cluster_tls.h Outdated Show resolved Hide resolved
bjosv added 6 commits January 22, 2025 00:43
These flags will be replaced by options and can be set
using these new APIs instead:

- valkeyClusterConnectWithOptions
- valkeyClusterAsyncConnectWithOptions

Signed-off-by: Björn Svensson <[email protected]>
Signed-off-by: Björn Svensson <[email protected]>
Signed-off-by: Björn Svensson <[email protected]>
@bjosv bjosv marked this pull request as ready for review January 22, 2025 10:24
Copy link
Collaborator

@zuiderkwast zuiderkwast left a comment

Choose a reason for hiding this comment

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

Finally made a pass on this PR. Looks good, but can't we remove more connect variants? It seems like connect-with-options is the only connect API we need?

docs/cluster.md Outdated Show resolved Hide resolved
docs/cluster.md Outdated Show resolved Hide resolved
docs/cluster.md Outdated Show resolved Hide resolved
docs/cluster.md Outdated Show resolved Hide resolved
docs/cluster.md Outdated Show resolved Hide resolved
src/cluster.c Outdated Show resolved Hide resolved
src/cluster.c Outdated Show resolved Hide resolved
@@ -2823,64 +2792,76 @@ valkeyClusterGetValkeyAsyncContext(valkeyClusterAsyncContext *acc,
return ac;
}

valkeyClusterAsyncContext *valkeyClusterAsyncContextInit(void) {
valkeyClusterAsyncContext *valkeyClusterAsyncContextInit(const valkeyClusterOptions *options) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there any point in supporting init without connect?

valkeyClusterAsyncConnectWithOptions would be enough, wouldn't it?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hm.... is it event loop related? The event loop needs to be attache between init and connect?

src/cluster.c Show resolved Hide resolved
include/valkey/cluster.h Outdated Show resolved Hide resolved
bjosv added 11 commits January 29, 2025 11:29
The option VALKEY_OPT_USE_CLUSTER_NODES can be used to
change to `cluster nodes`.

Signed-off-by: Björn Svensson <[email protected]>
This change makes cluster_tls.[c.h] files superfluous.

Signed-off-by: Björn Svensson <[email protected]>
Signed-off-by: Björn Svensson <[email protected]>
Use similar naming as option `connect_callback` for the blocking API.

Signed-off-by: Björn Svensson <[email protected]>
Signed-off-by: Björn Svensson <[email protected]>
Copy link
Collaborator

@zuiderkwast zuiderkwast left a comment

Choose a reason for hiding this comment

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

Looks mostly great. A large change that isn't very well explained in the docs is that you now attach the event loop to the options, instead of to the acc. We need to improve this part, also in the migration guide because it's an important and non-trivial change.

opt.password = "password" // Authentication; libvalkey sends the `AUTH` command.

// Enable TLS using a prepared `valkeyTLSContext` when connecting.
options.tls = tlsCtx;
Copy link
Collaborator

Choose a reason for hiding this comment

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

The valkeyClusterOptions variable is called opt in this example, not options.

// handle error
valkeyClusterOptions opt = {0};
opt.initial_nodes = "127.0.0.1:6379,127.0.0.1:6380"; // Addresses to initially connect to.
opt.options = VALKEY_OPT_USE_CLUSTER_NODES; // See available flags below.
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's a bit odd to have an options field in the options struct. Is it a big change for users if we rename it to flags? Matching standalone options, etc.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I used the name options for this field to match how it's named in valkeyOptions (which also has an options which takes VALKEY_OPT_*.). I guess we should change both in that case.

When contexts are initiated we keep the given option-flags in a context-field named flags, but here we also use it to keep internal state, both in cluster contexts and standalone.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We can keep options then. If we change to flags, it would imply all the macro names that contain VALKEY_OPT too. It would be too big change maybe.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, it getting large then. We can think about it, and possibly replace them all in a separate PR afterwards.


| Flag | Description |
| --- | --- |
| VALKEY\_OPT\_USE\_CLUSTER\_NODES | Tells libvalkey to use the command `CLUSTER NODES` when updating its slot map (cluster topology).<br>Libvalkey uses `CLUSTER SLOTS` by default. |
Copy link
Collaborator

Choose a reason for hiding this comment

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

If you use backticks around these constants, you don't need to escape the underscore.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ah nice! That makes it readable when "raw-reading" from a terminal, will update standalone.md too.

@@ -27,6 +27,9 @@ The type `sds` is removed from the public API.

## Migrating from `hiredis-cluster` 0.14.0

The command used to update the internal slot map is changed to `CLUSTER SLOTS`.
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
The command used to update the internal slot map is changed to `CLUSTER SLOTS`.
The default command to update the internal slot map is changed to `CLUSTER SLOTS`.

@@ -194,18 +235,7 @@ The first alternative is to use the function `valkeyClusterAsyncConnect`, which
Any command sent by the user thereafter will create a new non-blocking connection, unless a non-blocking connection already exists to the destination.
Copy link
Collaborator

Choose a reason for hiding this comment

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

(I can't comment on the lines above.) The async API doc starts like this:

Asynchronous API

Connecting

There are two alternative ways to initiate a cluster client, which also determines how the client behaves during the initial connect.
The first alternative is to use the function valkeyClusterAsyncConnect, which initially connects to the cluster in a blocking fashion and waits for the slot map before returning.

... and then the variant with init + connect2 is described.

But I checked cluster.h and I think we deleted the blocking connect and renamed connect2 to connect. We don't have any blocking valkeyClusterAsyncConnect anymore, do we?

I think the doc should first describe this variant:

  1. Create options struct
  2. Attach event loop to options
  3. valkeyClusterAsyncConnectWithOptions
valkeyClusterOptions options = {
    .initial_nodes = "127.0.0.1:7000";
};
valkeyClusterOptionsUseLibev(&options, EV_DEFAULT);
valkeyClusterAsyncContext *acc = valkeyClusterAsyncConnectWithOptions(&options);

and then the second variant with one more step acc = init(options); connect(acc).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oh, this part doesn't seem finished, there are a lot of empty lines too :( I will update.

Comment on lines +30 to +33
* The cluster client initiation procedure is changed and `valkeyClusterOptions`
should be used to specify options when creating a context.
The `examples` directory in this repository contains some common client
initiation examples that might be helpful.
Copy link
Collaborator

@zuiderkwast zuiderkwast Jan 30, 2025

Choose a reason for hiding this comment

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

We can also link to cluster.md from this migration guide, right? I think cluster.md should have some example of async connect with options.

We should be able to link just like [Link](cluster.md#section)

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.

2 participants