Skip to content

Commit a4fad64

Browse files
committed
Make driver override server timeout for system queries
Scylla have an ability to override server timeout by appending `USING TIMEOUT <timeout>ms` to the query Make driver add `USING TIMEOUT <control_connection_timeout*1000>ms` for scylla connections
1 parent 7e0b02d commit a4fad64

File tree

7 files changed

+338
-96
lines changed

7 files changed

+338
-96
lines changed

cassandra/cluster.py

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from __future__ import absolute_import
2020

2121
import atexit
22+
import datetime
2223
from binascii import hexlify
2324
from collections import defaultdict
2425
from collections.abc import Mapping
@@ -66,7 +67,7 @@
6667
RESULT_KIND_SET_KEYSPACE, RESULT_KIND_ROWS,
6768
RESULT_KIND_SCHEMA_CHANGE, ProtocolHandler,
6869
RESULT_KIND_VOID, ProtocolException)
69-
from cassandra.metadata import Metadata, protect_name, murmur3, _NodeInfo
70+
from cassandra.metadata import Metadata, protect_name, murmur3, _NodeInfo, SchemaQueryMessage
7071
from cassandra.policies import (TokenAwarePolicy, DCAwareRoundRobinPolicy, SimpleConvictionPolicy,
7172
ExponentialReconnectionPolicy, HostDistance,
7273
RetryPolicy, IdentityTranslator, NoSpeculativeExecutionPlan,
@@ -82,7 +83,7 @@
8283
from cassandra.marshal import int64_pack
8384
from cassandra.tablets import Tablet, Tablets
8485
from cassandra.timestamps import MonotonicTimestampGenerator
85-
from cassandra.util import _resolve_contact_points_to_string_map, Version
86+
from cassandra.util import _resolve_contact_points_to_string_map, Version, add_timeout_to_query
8687

8788
from cassandra.datastax.insights.reporter import MonitorReporter
8889
from cassandra.datastax.insights.util import version_supports_insights
@@ -1033,6 +1034,12 @@ def default_retry_policy(self, policy):
10331034
or to disable the shardaware port (advanced shardaware)
10341035
"""
10351036

1037+
metadata_request_timeout = datetime.timedelta(seconds=2)
1038+
"""
1039+
Timeout for all queries used by driver it self.
1040+
Supported only by Scylla clusters.
1041+
"""
1042+
10361043
@property
10371044
def schema_metadata_enabled(self):
10381045
"""
@@ -1148,7 +1155,9 @@ def __init__(self,
11481155
client_id=None,
11491156
cloud=None,
11501157
scylla_cloud=None,
1151-
shard_aware_options=None):
1158+
shard_aware_options=None,
1159+
metadata_request_timeout: datetime.timedelta | None = datetime.timedelta(seconds=2),
1160+
):
11521161
"""
11531162
``executor_threads`` defines the number of threads in a pool for handling asynchronous tasks such as
11541163
extablishing connection pools or refreshing metadata.
@@ -1240,6 +1249,8 @@ def __init__(self,
12401249
self.no_compact = no_compact
12411250

12421251
self.auth_provider = auth_provider
1252+
if metadata_request_timeout is not None:
1253+
self.metadata_request_timeout = metadata_request_timeout
12431254

12441255
if load_balancing_policy is not None:
12451256
if isinstance(load_balancing_policy, type):
@@ -3549,6 +3560,7 @@ class PeersQueryType(object):
35493560
_is_shutdown = False
35503561
_timeout = None
35513562
_protocol_version = None
3563+
_metadata_request_timeout: datetime.timedelta | None = None
35523564

35533565
_schema_event_refresh_window = None
35543566
_topology_event_refresh_window = None
@@ -3648,7 +3660,7 @@ def _reconnect_internal(self):
36483660
(conn, _) = self._connect_host_in_lbp()
36493661
if conn is not None:
36503662
return conn
3651-
3663+
36523664
# Try to re-resolve hostnames as a fallback when all hosts are unreachable
36533665
self._cluster._resolve_hostnames()
36543666

@@ -3689,11 +3701,16 @@ def _try_connect(self, host):
36893701
"registering watchers and refreshing schema and topology",
36903702
connection)
36913703

3704+
host.sharding_info = connection.features.sharding_info
3705+
36923706
# Indirect way to determine if conencted to a ScyllaDB cluster, which does not support peers_v2
36933707
# If sharding information is available, it's a ScyllaDB cluster, so do not use peers_v2 table.
36943708
if connection.features.sharding_info is not None:
36953709
self._uses_peers_v2 = False
3696-
3710+
3711+
# Cassandra does not support "USING TIMEOUT"
3712+
self._metadata_request_timeout = None if connection.features.sharding_info is None \
3713+
else datetime.timedelta(seconds=self._cluster.control_connection_timeout)
36973714
self._tablets_routing_v1 = connection.features.tablets_routing_v1
36983715

36993716
# use weak references in both directions
@@ -3710,8 +3727,10 @@ def _try_connect(self, host):
37103727

37113728
sel_peers = self._get_peers_query(self.PeersQueryType.PEERS, connection)
37123729
sel_local = self._SELECT_LOCAL if self._token_meta_enabled else self._SELECT_LOCAL_NO_TOKENS
3713-
peers_query = QueryMessage(query=sel_peers, consistency_level=ConsistencyLevel.ONE)
3714-
local_query = QueryMessage(query=sel_local, consistency_level=ConsistencyLevel.ONE)
3730+
peers_query = SchemaQueryMessage(query=sel_peers, consistency_level=ConsistencyLevel.ONE,
3731+
custom_timeout=self._metadata_request_timeout)
3732+
local_query = SchemaQueryMessage(query=sel_local, consistency_level=ConsistencyLevel.ONE,
3733+
custom_timeout=self._metadata_request_timeout)
37153734
(peers_success, peers_result), (local_success, local_result) = connection.wait_for_responses(
37163735
peers_query, local_query, timeout=self._timeout, fail_on_error=False)
37173736

@@ -3830,7 +3849,12 @@ def _refresh_schema(self, connection, preloaded_results=None, schema_agreement_w
38303849
log.debug("Skipping schema refresh due to lack of schema agreement")
38313850
return False
38323851

3833-
self._cluster.metadata.refresh(connection, self._timeout, fetch_size=self._schema_meta_page_size, **kwargs)
3852+
self._cluster.metadata.refresh(
3853+
connection,
3854+
self._timeout,
3855+
fetch_size=self._schema_meta_page_size,
3856+
metadata_request_timeout=self._actual_metadata_request_timeout,
3857+
**kwargs)
38343858

38353859
return True
38363860

@@ -3861,8 +3885,10 @@ def _refresh_node_list_and_token_map(self, connection, preloaded_results=None,
38613885
else:
38623886
log.debug("[control connection] Refreshing node list and token map")
38633887
sel_local = self._SELECT_LOCAL
3864-
peers_query = QueryMessage(query=sel_peers, consistency_level=cl)
3865-
local_query = QueryMessage(query=sel_local, consistency_level=cl)
3888+
peers_query = SchemaQueryMessage(query=sel_peers, consistency_level=cl,
3889+
custom_timeout=self._metadata_request_timeout)
3890+
local_query = SchemaQueryMessage(query=sel_local, consistency_level=cl,
3891+
custom_timeout=self._metadata_request_timeout)
38663892
peers_result, local_result = connection.wait_for_responses(
38673893
peers_query, local_query, timeout=self._timeout)
38683894

@@ -3917,8 +3943,11 @@ def _refresh_node_list_and_token_map(self, connection, preloaded_results=None,
39173943
# local rpc_address has not been queried yet, try to fetch it
39183944
# separately, which might fail because C* < 2.1.6 doesn't have rpc_address
39193945
# in system.local. See CASSANDRA-9436.
3920-
local_rpc_address_query = QueryMessage(query=self._SELECT_LOCAL_NO_TOKENS_RPC_ADDRESS,
3921-
consistency_level=ConsistencyLevel.ONE)
3946+
local_rpc_address_query = SchemaQueryMessage(
3947+
query=self._SELECT_LOCAL_NO_TOKENS_RPC_ADDRESS,
3948+
consistency_level=ConsistencyLevel.ONE,
3949+
custom_timeout=self._metadata_request_timeout,
3950+
)
39223951
success, local_rpc_address_result = connection.wait_for_response(
39233952
local_rpc_address_query, timeout=self._timeout, fail_on_error=False)
39243953
if success:
@@ -4153,8 +4182,10 @@ def wait_for_schema_agreement(self, connection=None, preloaded_results=None, wai
41534182
select_peers_query = self._get_peers_query(self.PeersQueryType.PEERS_SCHEMA, connection)
41544183

41554184
while elapsed < total_timeout:
4156-
peers_query = QueryMessage(query=select_peers_query, consistency_level=cl)
4157-
local_query = QueryMessage(query=self._SELECT_SCHEMA_LOCAL, consistency_level=cl)
4185+
peers_query = SchemaQueryMessage(query=select_peers_query, consistency_level=cl,
4186+
custom_timeout=self._metadata_request_timeout)
4187+
local_query = SchemaQueryMessage(query=self._SELECT_SCHEMA_LOCAL, consistency_level=cl,
4188+
custom_timeout=self._metadata_request_timeout)
41584189
try:
41594190
timeout = min(self._timeout, total_timeout - elapsed)
41604191
peers_result, local_result = connection.wait_for_responses(

0 commit comments

Comments
 (0)