Skip to content

Commit 94ad486

Browse files
cicoylesicoyle
andauthored
No 60s timeout by default (#956)
* no 60s timeout by default Signed-off-by: Cassandra Coyle <cassie@diagrid.io> * add test and fix lint Signed-off-by: Cassandra Coyle <cassie@diagrid.io> * add test Signed-off-by: Cassandra Coyle <cassie@diagrid.io> --------- Signed-off-by: Cassandra Coyle <cassie@diagrid.io> Co-authored-by: Sam <sam@diagrid.io>
1 parent 0ab9f0e commit 94ad486

5 files changed

Lines changed: 69 additions & 8 deletions

File tree

dapr/aio/clients/grpc/interceptors.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,14 @@ class _ClientCallDetailsAsync(
4141

4242
class DaprClientTimeoutInterceptorAsync(UnaryUnaryClientInterceptor):
4343
def intercept_unary_unary(self, continuation, client_call_details, request):
44-
# If a specific timeout is not set, create a new ClientCallDetails with the default timeout
45-
if client_call_details.timeout is None:
44+
# Only apply a deadline when DAPR_API_TIMEOUT_SECONDS is explicitly configured.
45+
# Without an explicit setting there is no SDK-level default deadline: Dapr's own
46+
# resiliency policies and component timeouts act as the authoritative bounds for
47+
# long-running operations such as LLM calls and workflow activities.
48+
if settings.DAPR_API_TIMEOUT_SECONDS is not None and client_call_details.timeout is None:
4649
new_client_call_details = _ClientCallDetailsAsync(
4750
client_call_details.method,
48-
settings.DAPR_API_TIMEOUT_SECONDS,
51+
float(settings.DAPR_API_TIMEOUT_SECONDS),
4952
client_call_details.metadata,
5053
client_call_details.credentials,
5154
client_call_details.wait_for_ready,

dapr/clients/grpc/interceptors.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,14 @@ class _ClientCallDetails(
2727

2828
class DaprClientTimeoutInterceptor(UnaryUnaryClientInterceptor):
2929
def intercept_unary_unary(self, continuation, client_call_details, request):
30-
# If a specific timeout is not set, create a new ClientCallDetails with the default timeout
31-
if client_call_details.timeout is None:
30+
# Only apply a deadline when DAPR_API_TIMEOUT_SECONDS is explicitly configured.
31+
# Without an explicit setting there is no SDK-level default deadline: Dapr's own
32+
# resiliency policies and component timeouts act as the authoritative bounds for
33+
# long-running operations such as LLM calls and workflow activities.
34+
if settings.DAPR_API_TIMEOUT_SECONDS is not None and client_call_details.timeout is None:
3235
new_client_call_details = _ClientCallDetails(
3336
client_call_details.method,
34-
settings.DAPR_API_TIMEOUT_SECONDS,
37+
float(settings.DAPR_API_TIMEOUT_SECONDS),
3538
client_call_details.metadata,
3639
client_call_details.credentials,
3740
client_call_details.wait_for_ready,

dapr/conf/global_settings.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
DAPR_HEALTH_TIMEOUT = 60 # seconds
2929

3030
DAPR_API_MAX_RETRIES = 0
31-
DAPR_API_TIMEOUT_SECONDS = 60
31+
DAPR_API_TIMEOUT_SECONDS = (
32+
None # No default deadline — set DAPR_API_TIMEOUT_SECONDS env var to impose one
33+
)
3234

3335
DAPR_API_METHOD_INVOCATION_PROTOCOL = 'http'
3436

tests/clients/test_timeout_interceptor.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121

2222

2323
class DaprClientTimeoutInterceptorTests(unittest.TestCase):
24-
def test_intercept_unary_unary_with_timeout(self):
24+
@patch.object(settings, 'DAPR_API_TIMEOUT_SECONDS', 7)
25+
def test_intercept_unary_unary_global_timeout_with_per_call_timeout(self):
2526
continuation = Mock()
2627
request = Mock()
2728
client_call_details = Mock()
@@ -36,6 +37,8 @@ def test_intercept_unary_unary_with_timeout(self):
3637
continuation, client_call_details, request
3738
)
3839
continuation.assert_called_once_with(client_call_details, request)
40+
called_client_call_details = continuation.call_args[0][0]
41+
self.assertEqual(10, called_client_call_details.timeout)
3942

4043
@patch.object(settings, 'DAPR_API_TIMEOUT_SECONDS', 7)
4144
def test_intercept_unary_unary_without_timeout(self):
@@ -54,3 +57,37 @@ def test_intercept_unary_unary_without_timeout(self):
5457
)
5558
called_client_call_details = continuation.call_args[0][0]
5659
self.assertEqual(7, called_client_call_details.timeout)
60+
61+
@patch.object(settings, 'DAPR_API_TIMEOUT_SECONDS', None)
62+
def test_intercept_unary_unary_no_global_timeout_with_per_call_timeout(self):
63+
continuation = Mock()
64+
request = Mock()
65+
client_call_details = Mock()
66+
client_call_details.method = 'method'
67+
client_call_details.timeout = 10
68+
client_call_details.metadata = 'metadata'
69+
client_call_details.credentials = 'credentials'
70+
client_call_details.wait_for_ready = 'wait_for_ready'
71+
client_call_details.compression = 'compression'
72+
73+
DaprClientTimeoutInterceptor().intercept_unary_unary(
74+
continuation, client_call_details, request
75+
)
76+
continuation.assert_called_once_with(client_call_details, request)
77+
78+
@patch.object(settings, 'DAPR_API_TIMEOUT_SECONDS', None)
79+
def test_intercept_unary_unary_no_global_timeout_no_per_call_timeout(self):
80+
continuation = Mock()
81+
request = Mock()
82+
client_call_details = Mock()
83+
client_call_details.method = 'method'
84+
client_call_details.timeout = None
85+
client_call_details.metadata = 'metadata'
86+
client_call_details.credentials = 'credentials'
87+
client_call_details.wait_for_ready = 'wait_for_ready'
88+
client_call_details.compression = 'compression'
89+
90+
DaprClientTimeoutInterceptor().intercept_unary_unary(
91+
continuation, client_call_details, request
92+
)
93+
continuation.assert_called_once_with(client_call_details, request)

tests/clients/test_timeout_interceptor_async.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,19 @@ def test_intercept_unary_unary_without_timeout(self):
5252
)
5353
called_client_call_details = continuation.call_args[0][0]
5454
self.assertEqual(7, called_client_call_details.timeout)
55+
56+
@patch.object(settings, 'DAPR_API_TIMEOUT_SECONDS', None)
57+
def test_intercept_unary_unary_no_global_timeout_no_per_call_timeout(self):
58+
continuation = Mock()
59+
request = Mock()
60+
client_call_details = Mock()
61+
client_call_details.method = 'method'
62+
client_call_details.timeout = None
63+
client_call_details.metadata = 'metadata'
64+
client_call_details.credentials = 'credentials'
65+
client_call_details.wait_for_ready = 'wait_for_ready'
66+
67+
DaprClientTimeoutInterceptorAsync().intercept_unary_unary(
68+
continuation, client_call_details, request
69+
)
70+
continuation.assert_called_once_with(client_call_details, request)

0 commit comments

Comments
 (0)