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

Python: enable routing by node address. #1038

Merged
merged 8 commits into from
Mar 6, 2024

Conversation

nihohit
Copy link
Contributor

@nihohit nihohit commented Feb 26, 2024

Issue #, if available:

Description of changes:

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@nihohit nihohit requested a review from a team as a code owner February 26, 2024 08:50
@nihohit nihohit force-pushed the python-address-routing branch from 6578a66 to 0cb5414 Compare February 26, 2024 09:41
@@ -48,6 +48,18 @@ def __init__(self, slot_type: SlotType, slot_id: int) -> None:
self.slot_id = slot_id


class ByAddressRoute(Route):
def __init__(self, host: str, port: Optional[int] = None) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

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

we need to specify the format of the host (ip:tcp_port) and handle erroneous values, or make host -> host_ip.
Document that if port is None than a default will be used

@nihohit nihohit force-pushed the python-address-routing branch 2 times, most recently from ef1914b to 32edaaa Compare February 26, 2024 10:43
@@ -48,6 +48,24 @@ def __init__(self, slot_type: SlotType, slot_id: int) -> None:
self.slot_id = slot_id


class ByAddressRoute(Route):
def __init__(self, host: str, port: Optional[int] = None) -> None:
"""Routes a request to a node by its DNS address
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think DNS is right, as it can be also IP.
maybe change to

Routes a request to a node based on its host address and IP

Copy link
Contributor Author

Choose a reason for hiding this comment

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

when/how can it be IP? I'm not sure that it will work. Also, why would the user have the IP of the machine?

Copy link
Collaborator

Choose a reason for hiding this comment

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

how will we support when nodes dont have the dns but only the IP ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🤷
This PR aligns the python API with the node API. AFAIK we don't support connecting using an IP, so I'm not sure that just passing the IP as a string will work. I recommend spinning off IP support in routing to a separate PR, since I believe it will require core & redis-rs work.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it depends on how user configured the cluster. If nodes know each other by IP, so response of cluster slots would contain IPs only and glide core would know IPs only.
Probably, we need to refer there to cluster configuration, like

Suggested change
"""Routes a request to a node by its DNS address
"""Routes a request to a node by its address given on cluster configuration

Copy link
Collaborator

@barshaul barshaul Feb 28, 2024

Choose a reason for hiding this comment

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

when/how can it be IP? I'm not sure that it will work. Also, why would the user have the IP of the machine?

If the cluster is configured with TLS disabled, the nodes will be shown in cluster slots/nodes with their IPs, rather than their DNS. Yuri is right that it depends on server.

"""Routes a request to a node by its DNS address

Args:
host (str): The DNS name of the node. If `port` is not provided, should be in the `{DNS}:{port}` format.
Copy link
Collaborator

Choose a reason for hiding this comment

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

same regarding DNS

Copy link
Collaborator

Choose a reason for hiding this comment

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

same as my comment above - should we support IP host addresses also?

if port == None:
split = host.split(":")
host = split[0]
port = int(split[1])
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 potential error, we should catch this exception and raise appropriate client error

Copy link
Collaborator

Choose a reason for hiding this comment

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

May be use a 3rd lib which does all checks for us?
Consider that a user may give two different ports or port out of range.

port = int(split[1])

self.host = host
self.port = port if port else 0
Copy link
Collaborator

Choose a reason for hiding this comment

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

How can port be None at this point?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ask mypy. I only added this to satisfy it 🤷 .

Copy link
Collaborator

Choose a reason for hiding this comment

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

then lets do something like:

if port is None:
            split = host.split(":")
            self.host = split[0]
            self.port = int(split[1])
else:
            self.host = host
            self.port = port

port (Optional[int]): The port the node communicates on.
"""
super().__init__()
if port == None:
Copy link
Collaborator

Choose a reason for hiding this comment

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

if port is None

@@ -1416,6 +1417,36 @@ async def test_info_random_route(self, redis_client: RedisClusterClient):
assert isinstance(info, str)
assert "# Server" in info

@pytest.mark.parametrize("cluster_mode", [True])
Copy link
Collaborator

Choose a reason for hiding this comment

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

what about the test for failing if port isn't passed?

@nihohit
Copy link
Contributor Author

nihohit commented Feb 26, 2024

@barshaul @ikolomi answered / fixed comments.

@Yury-Fridlyand Yury-Fridlyand added the python Python wrapper label Feb 26, 2024
@@ -56,7 +57,7 @@ export type SlotKeyTypes = {
export type RouteByAddress = {
type: "routeByAddress";
/**
* DNS name of the host.
* The name of the node. If `port` is not provided, should be in the `{DNS/ip}:{port}` format, as returned from the cluster when sending a request to multiple nodes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think it's a good way of explaining it, as the results of some commands that are being sent to multiple nodes are being aggregated to a single response.. so the user really needs to know the client to understand that. Can you check if we can use cluster nodes/slots output to explain what should be passed?

@@ -48,6 +49,29 @@ def __init__(self, slot_type: SlotType, slot_id: int) -> None:
self.slot_id = slot_id


class ByAddressRoute(Route):
def __init__(self, host: str, port: Optional[int] = None) -> None:
"""Routes a request to a node by its DNS address
Copy link
Collaborator

Choose a reason for hiding this comment

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

Again- "DNS" isn't right here and in the documentation below

if len(split) < 2:
raise RequestError(
"No port provided, expected host to be formatted as {hostname}:{port}`. Received "
+ host
Copy link
Collaborator

Choose a reason for hiding this comment

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

Minor: use f"...{host}"

@nihohit nihohit force-pushed the python-address-routing branch from debba53 to d42f109 Compare March 6, 2024 16:40
Copy link
Collaborator

@Yury-Fridlyand Yury-Fridlyand left a comment

Choose a reason for hiding this comment

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

Please, add a UT to cover parsing error cases, like address line is "abc:def"
Please, add an IT with wrong address and/or port

node/src/RedisClusterClient.ts Outdated Show resolved Hide resolved
python/python/glide/routes.py Outdated Show resolved Hide resolved
@nihohit nihohit force-pushed the python-address-routing branch from b018c97 to 13dc9ca Compare March 6, 2024 17:39
@shachlanAmazon shachlanAmazon merged commit 25a30bd into valkey-io:main Mar 6, 2024
11 checks passed
@nihohit nihohit deleted the python-address-routing branch March 6, 2024 20:47
cyip10 pushed a commit to Bit-Quill/valkey-glide that referenced this pull request Jun 24, 2024
* Python: enable routing by node address.

* Added correct error handling to the split.

* Fix check

* fix

* Updated host's documentation.

* fix docs

* Update python/python/glide/routes.py

Co-authored-by: Yury-Fridlyand <[email protected]>

* Update node/src/RedisClusterClient.ts

Co-authored-by: Yury-Fridlyand <[email protected]>

---------

Co-authored-by: Shachar Langbeheim <[email protected]>
Co-authored-by: Yury-Fridlyand <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
python Python wrapper
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants