-
Notifications
You must be signed in to change notification settings - Fork 7
added get_replica_connections function #72
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
base: main
Are you sure you want to change the base?
Changes from 6 commits
e7beff6
6a717ab
0791c7e
c77580e
5ee68b7
c4dc33a
2c20a1e
99b6671
dd8a4ad
8eed87f
e646320
4a3d585
a1262e0
199a1e5
71622fe
9f261fc
9d21e95
6aad7bd
2a96be0
b693987
519b9dd
557f04f
222cfb4
a9f597e
ac8471e
cfd0864
65e41d0
d112322
ad7cedd
ac4cfa4
5a444db
4cc0b6a
51d4d90
cb8cd2e
1ad3162
4d4c1ac
263e8bf
af4f748
b1d6c41
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -75,6 +75,7 @@ def __init__( | |||||||||||||||||||||||
| dynamic_startup_nodes=True, | ||||||||||||||||||||||||
| url=None, | ||||||||||||||||||||||||
| address_remap=None, | ||||||||||||||||||||||||
| decode_responses=True | ||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| conn = redis.Redis( | ||||||||||||||||||||||||
|
|
@@ -92,7 +93,7 @@ def __init__( | |||||||||||||||||||||||
| encoding_errors=encoding_errors, | ||||||||||||||||||||||||
| charset=charset, | ||||||||||||||||||||||||
| errors=errors, | ||||||||||||||||||||||||
| decode_responses=True, | ||||||||||||||||||||||||
| decode_responses=decode_responses, | ||||||||||||||||||||||||
| retry_on_timeout=retry_on_timeout, | ||||||||||||||||||||||||
| retry_on_error=retry_on_error, | ||||||||||||||||||||||||
| ssl=ssl, | ||||||||||||||||||||||||
|
|
@@ -125,6 +126,7 @@ def __init__( | |||||||||||||||||||||||
| self.sentinel, self.service_name = Sentinel_Conn(conn, ssl) | ||||||||||||||||||||||||
| conn = self.sentinel.master_for(self.service_name, ssl=ssl) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if Is_Cluster(conn): | ||||||||||||||||||||||||
| conn = Cluster_Conn( | ||||||||||||||||||||||||
| conn, | ||||||||||||||||||||||||
|
|
@@ -225,6 +227,37 @@ def config_get(self, name: str) -> Union[int, str]: | |||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| return self.connection.execute_command(CONFIG_CMD, "GET", name)[1] | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| def get_replica_connections(self): | ||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||
| Retrieve a list of connections for Redis replica nodes. | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| This function determines the Redis setup (Sentinel or Cluster) and returns | ||||||||||||||||||||||||
| the hostnames and ports of the replicas. | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Returns: | ||||||||||||||||||||||||
| list of tuple: A list of (hostname, port) tuples representing the | ||||||||||||||||||||||||
| replica connections. | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Raises: | ||||||||||||||||||||||||
| ConnectionError: If unable to connect or retrieve information from | ||||||||||||||||||||||||
| the Redis setup. | ||||||||||||||||||||||||
| ValueError: If the `redis_mode` is neither Sentinel nor Cluster. | ||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||
| # decide if it's Sentinel or cluster | ||||||||||||||||||||||||
| redis_mode = self.connection.execute_command("info")['redis_mode'] | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
| redis_mode = self.connection.execute_command("info")['redis_mode'] | |
| try: | |
| info = self.connection.execute_command("info", section="server") | |
| redis_mode = info.get('redis_mode') | |
| if not redis_mode: | |
| raise ConnectionError("Unable to determine Redis mode") | |
| except Exception as e: | |
| raise ConnectionError(f"Failed to retrieve Redis mode: {str(e)}") |
Outdated
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.
🛠️ Refactor suggestion
Update deprecated Redis terminology
The code uses deprecated 'slave' terminology. Redis has moved to more inclusive language.
Update the terminology:
- replica_hostnames = self.sentinel.discover_slaves(service_name=self.service_name)
+ replica_hostnames = self.sentinel.discover_replicas(service_name=self.service_name)
- return [(flag['hostname'], int(ip_port.split(':')[1])) for ip_port, flag in data.items() if 'slave' in flag["flags"] and flag["hostname"]]
+ return [(flag.get('hostname', ip_port.split(':')[0]), int(ip_port.split(':')[1]))
+ for ip_port, flag in data.items()
+ if 'replica' in flag.get('flags', [])]Also applies to: 255-255
Outdated
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.
Update implementation to use modern Redis terminology and handle edge cases
The current implementation has several issues:
- Uses deprecated 'slave' terminology
- Assumes 'hostname' exists in cluster node flags
- Doesn't convert port to integer
- replica_hostnames = self.sentinel.discover_slaves(service_name=self.service_name)
- return [(host, port) for host, port in replica_hostnames]
+ try:
+ replica_hostnames = self.sentinel.discover_replicas(service_name=self.service_name)
+ return [(host, int(port)) for host, port in replica_hostnames]
+ except Exception as e:
+ raise ConnectionError(f"Failed to discover replicas: {str(e)}")
# For cluster mode:
- return [(flag['hostname'], ip_port.split(':')[1]) for ip_port, flag in data.items() if 'slave' in flag["flags"]]
+ result = []
+ for ip_port, flag in data.items():
+ if 'replica' in flag.get('flags', []):
+ try:
+ host = ip_port.split(':')[0] # Use IP as hostname
+ port = int(ip_port.split(':')[1])
+ result.append((host, port))
+ except (IndexError, ValueError) as e:
+ continue # Skip malformed entries
+ return resultAlso applies to: 254-255
Outdated
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.
Fix potential KeyError in cluster mode implementation
The current implementation assumes the presence of a 'hostname' key and doesn't handle potential errors.
Apply this diff:
- return [(flag['hostname'], ip_port.split(':')[1]) for ip_port, flag in data.items() if 'slave' in flag["flags"]]
+ result = []
+ for ip_port, flag in data.items():
+ if 'replica' in flag.get('flags', []): # Using 'replica' instead of 'slave'
+ try:
+ host = ip_port.split(':')[0] # Use IP as hostname
+ port = int(ip_port.split(':')[1])
+ result.append((host, port))
+ except (IndexError, ValueError) as e:
+ continue # Skip malformed entries
+ return result📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| return [(flag['hostname'], ip_port.split(':')[1]) for ip_port, flag in data.items() if 'slave' in flag["flags"]] | |
| result = [] | |
| for ip_port, flag in data.items(): | |
| if 'replica' in flag.get('flags', []): # Using 'replica' instead of 'slave' | |
| try: | |
| host = ip_port.split(':')[0] # Use IP as hostname | |
| port = int(ip_port.split(':')[1]) | |
| result.append((host, port)) | |
| except (IndexError, ValueError) as e: | |
| continue # Skip malformed entries | |
| return result |
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 248-254: falkordb/falkordb.py#L248-L254
Added lines #L248 - L254 were not covered by tests
Outdated
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.
Fix undefined variable reference
The error message references redis_mode but the variable is named mode.
Apply this diff:
- raise ValueError(f"Unsupported Redis mode: {redis_mode}")
+ raise ValueError(f"Unsupported Redis mode: {mode}")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| raise ValueError(f"Unsupported Redis mode: {redis_mode}") | |
| raise ValueError(f"Unsupported Redis mode: {mode}") |
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 256-256: falkordb/falkordb.py#L256
Added line #L256 was not covered by tests
🪛 Ruff
256-256: redis_mode may be undefined, or defined from star imports
(F405)
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.
💡 Codebase verification
Missing test coverage for get_replica_connections method confirmed
The method requires test coverage for:
- Sentinel mode replica discovery
- Cluster mode replica discovery
- Error handling for connection failures
- Invalid mode handling
Example test structure in tests/test_db.py:
def test_get_replica_connections_sentinel():
# Test sentinel mode with mocked sentinel.discover_slaves
def test_get_replica_connections_cluster():
# Test cluster mode with mocked cluster_nodes
def test_get_replica_connections_errors():
# Test connection errors and invalid modes🔗 Analysis chain
Add test coverage for the new method
The new get_replica_connections method lacks test coverage for critical paths.
Would you like me to help create comprehensive test cases covering:
- Sentinel mode replica discovery
- Cluster mode replica discovery
- Error handling scenarios
- Invalid mode handling
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for existing tests of the new method
fd test_.+\.py$ | xargs rg "get_replica_connections"
Length of output: 53
Script:
#!/bin/bash
# Let's first check if there are any test files in the repository
fd "test.*\.py$"
# Then let's check the content of the falkordb.py file to understand the test requirements better
cat falkordb/falkordb.py
Length of output: 9548
Script:
#!/bin/bash
# Let's check test_db.py as it's likely to contain tests for FalkorDB class methods
cat tests/test_db.py
# Also check if there are any mock or fixture utilities for testing
fd "conftest\.py$"
Length of output: 1366
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 248-251: falkordb/falkordb.py#L248-L251
Added lines #L248 - L251 were not covered by tests
[warning] 253-258: falkordb/falkordb.py#L253-L258
Added lines #L253 - L258 were not covered by tests
[warning] 260-260: falkordb/falkordb.py#L260
Added line #L260 was not covered by tests
🪛 Ruff
251-251: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
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.
🛠️ Refactor suggestion
Avoid wildcard imports to improve code clarity
Using wildcard imports can pollute the namespace and make it harder to track dependencies. Explicit imports enhance code readability and maintainability.
🧰 Tools
🪛 Ruff
Import
Is_SentinelandSentinel_Connexplicitly to avoid undefined namesThe functions
Is_SentinelandSentinel_Connmay be undefined if not imported properly. Wildcard imports (e.g.,from .sentinel import *) can lead to unclear code and potentialNameErrors.Apply this diff to fix the imports:
Similarly, update the cluster imports:
🧰 Tools
🪛 Ruff