Skip to content

Commit 9e9ded4

Browse files
authored
Merge pull request #361 from scylladb/dk/320-python-implementation-of-decouple-schema-fetch-queries-from-server-side-timeouts
Decouple schema fetch queries timeouts from server side timeouts
2 parents c0c016a + 7a4ae44 commit 9e9ded4

File tree

9 files changed

+305
-99
lines changed

9 files changed

+305
-99
lines changed

cassandra/cluster.py

Lines changed: 42 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
@@ -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, maybe_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=None,
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 = 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

@@ -3693,7 +3705,10 @@ def _try_connect(self, host):
36933705
# If sharding information is available, it's a ScyllaDB cluster, so do not use peers_v2 table.
36943706
if connection.features.sharding_info is not None:
36953707
self._uses_peers_v2 = False
3696-
3708+
3709+
# Cassandra does not support "USING TIMEOUT"
3710+
self._metadata_request_timeout = None if connection.features.sharding_info is None \
3711+
else datetime.timedelta(seconds=self._cluster.control_connection_timeout)
36973712
self._tablets_routing_v1 = connection.features.tablets_routing_v1
36983713

36993714
# use weak references in both directions
@@ -3710,8 +3725,10 @@ def _try_connect(self, host):
37103725

37113726
sel_peers = self._get_peers_query(self.PeersQueryType.PEERS, connection)
37123727
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)
3728+
peers_query = QueryMessage(query=maybe_add_timeout_to_query(sel_peers, self._metadata_request_timeout),
3729+
consistency_level=ConsistencyLevel.ONE)
3730+
local_query = QueryMessage(query=maybe_add_timeout_to_query(sel_local, self._metadata_request_timeout),
3731+
consistency_level=ConsistencyLevel.ONE)
37153732
(peers_success, peers_result), (local_success, local_result) = connection.wait_for_responses(
37163733
peers_query, local_query, timeout=self._timeout, fail_on_error=False)
37173734

@@ -3722,7 +3739,8 @@ def _try_connect(self, host):
37223739
# error with the peers v2 query, fallback to peers v1
37233740
self._uses_peers_v2 = False
37243741
sel_peers = self._get_peers_query(self.PeersQueryType.PEERS, connection)
3725-
peers_query = QueryMessage(query=sel_peers, consistency_level=ConsistencyLevel.ONE)
3742+
peers_query = QueryMessage(query=maybe_add_timeout_to_query(sel_peers, self._metadata_request_timeout),
3743+
consistency_level=ConsistencyLevel.ONE)
37263744
peers_result = connection.wait_for_response(
37273745
peers_query, timeout=self._timeout)
37283746

@@ -3830,7 +3848,12 @@ def _refresh_schema(self, connection, preloaded_results=None, schema_agreement_w
38303848
log.debug("Skipping schema refresh due to lack of schema agreement")
38313849
return False
38323850

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

38353858
return True
38363859

@@ -3861,8 +3884,10 @@ def _refresh_node_list_and_token_map(self, connection, preloaded_results=None,
38613884
else:
38623885
log.debug("[control connection] Refreshing node list and token map")
38633886
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)
3887+
peers_query = QueryMessage(query=maybe_add_timeout_to_query(sel_peers, self._metadata_request_timeout),
3888+
consistency_level=cl)
3889+
local_query = QueryMessage(query=maybe_add_timeout_to_query(sel_local, self._metadata_request_timeout),
3890+
consistency_level=cl)
38663891
peers_result, local_result = connection.wait_for_responses(
38673892
peers_query, local_query, timeout=self._timeout)
38683893

@@ -3917,8 +3942,9 @@ def _refresh_node_list_and_token_map(self, connection, preloaded_results=None,
39173942
# local rpc_address has not been queried yet, try to fetch it
39183943
# separately, which might fail because C* < 2.1.6 doesn't have rpc_address
39193944
# 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)
3945+
local_rpc_address_query = QueryMessage(
3946+
query=maybe_add_timeout_to_query(self._SELECT_LOCAL_NO_TOKENS_RPC_ADDRESS, self._metadata_request_timeout),
3947+
consistency_level=ConsistencyLevel.ONE)
39223948
success, local_rpc_address_result = connection.wait_for_response(
39233949
local_rpc_address_query, timeout=self._timeout, fail_on_error=False)
39243950
if success:
@@ -4153,8 +4179,10 @@ def wait_for_schema_agreement(self, connection=None, preloaded_results=None, wai
41534179
select_peers_query = self._get_peers_query(self.PeersQueryType.PEERS_SCHEMA, connection)
41544180

41554181
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)
4182+
peers_query = QueryMessage(query=maybe_add_timeout_to_query(select_peers_query, self._metadata_request_timeout),
4183+
consistency_level=cl)
4184+
local_query = QueryMessage(query=maybe_add_timeout_to_query(self._SELECT_SCHEMA_LOCAL, self._metadata_request_timeout),
4185+
consistency_level=cl)
41584186
try:
41594187
timeout = min(self._timeout, total_timeout - elapsed)
41604188
peers_result, local_result = connection.wait_for_responses(

0 commit comments

Comments
 (0)