Skip to content

Commit 011799f

Browse files
committed
fix: copilot feedback
Signed-off-by: Ninad Kale <ninadkale200@gmail.com>
1 parent 7879792 commit 011799f

9 files changed

Lines changed: 148 additions & 98 deletions

File tree

dapr/actor/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
from dapr.actor.actor_interface import ActorInterface, actormethod
1717
from dapr.actor.client.proxy import ActorProxy, ActorProxyFactory
1818
from dapr.actor.id import ActorId
19-
from dapr.actor.runtime._failure_policy import ActorReminderFailurePolicy
2019
from dapr.actor.runtime.actor import Actor
20+
from dapr.actor.runtime.failure_policy import ActorReminderFailurePolicy
2121
from dapr.actor.runtime.remindable import Remindable
2222
from dapr.actor.runtime.runtime import ActorRuntime
2323

dapr/actor/runtime/_failure_policy.py

Lines changed: 3 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -13,93 +13,7 @@
1313
limitations under the License.
1414
"""
1515

16-
from datetime import timedelta
17-
from typing import Any, Dict, Optional
16+
# Backward-compatible shim — import from the public module instead.
17+
from dapr.actor.runtime.failure_policy import ActorReminderFailurePolicy
1818

19-
20-
class ActorReminderFailurePolicy:
21-
"""Defines what happens when an actor reminder fails to trigger.
22-
23-
Use :meth:`drop_policy` to discard failed ticks without retrying, or
24-
:meth:`constant_policy` to retry at a fixed interval.
25-
26-
Attributes:
27-
drop: whether this is a drop (no-retry) policy.
28-
interval: the retry interval for a constant policy.
29-
max_retries: the maximum number of retries for a constant policy.
30-
"""
31-
32-
def __init__(
33-
self,
34-
*,
35-
drop: bool = False,
36-
interval: Optional[timedelta] = None,
37-
max_retries: Optional[int] = None,
38-
):
39-
"""Creates a new :class:`ActorReminderFailurePolicy` instance.
40-
41-
Args:
42-
drop (bool): if True, creates a drop policy that discards the reminder
43-
tick on failure without retrying. Cannot be combined with interval
44-
or max_retries.
45-
interval (datetime.timedelta): the retry interval for a constant policy.
46-
max_retries (int): the maximum number of retries for a constant policy.
47-
If not set, retries indefinitely.
48-
49-
Raises:
50-
ValueError: if drop is combined with interval or max_retries, or if
51-
neither drop=True nor at least one of interval/max_retries is provided.
52-
"""
53-
if drop and (interval is not None or max_retries is not None):
54-
raise ValueError('drop policy cannot be combined with interval or max_retries')
55-
if not drop and interval is None and max_retries is None:
56-
raise ValueError('specify either drop=True or at least one of interval or max_retries')
57-
self._drop = drop
58-
self._interval = interval
59-
self._max_retries = max_retries
60-
61-
@classmethod
62-
def drop_policy(cls) -> 'ActorReminderFailurePolicy':
63-
"""Returns a policy that drops the reminder tick on failure (no retry)."""
64-
return cls(drop=True)
65-
66-
@classmethod
67-
def constant_policy(
68-
cls,
69-
interval: Optional[timedelta] = None,
70-
max_retries: Optional[int] = None,
71-
) -> 'ActorReminderFailurePolicy':
72-
"""Returns a policy that retries at a constant interval on failure.
73-
74-
Args:
75-
interval (datetime.timedelta): the time between retry attempts.
76-
max_retries (int): the maximum number of retry attempts. If not set,
77-
retries indefinitely.
78-
"""
79-
return cls(interval=interval, max_retries=max_retries)
80-
81-
@property
82-
def drop(self) -> bool:
83-
"""Returns True if this is a drop policy."""
84-
return self._drop
85-
86-
@property
87-
def interval(self) -> Optional[timedelta]:
88-
"""Returns the retry interval for a constant policy."""
89-
return self._interval
90-
91-
@property
92-
def max_retries(self) -> Optional[int]:
93-
"""Returns the maximum retries for a constant policy."""
94-
return self._max_retries
95-
96-
def as_dict(self) -> Dict[str, Any]:
97-
"""Gets :class:`ActorReminderFailurePolicy` as a dict object."""
98-
if self._drop:
99-
return {'drop': {}}
100-
d: Dict[str, Any] = {}
101-
if self._interval is not None:
102-
d['interval'] = self._interval
103-
if self._max_retries is not None:
104-
d['maxRetries'] = self._max_retries
105-
return {'constant': d}
19+
__all__ = ['ActorReminderFailurePolicy']

dapr/actor/runtime/_reminder_data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from datetime import timedelta
1818
from typing import Any, Dict, Optional
1919

20-
from dapr.actor.runtime._failure_policy import ActorReminderFailurePolicy
20+
from dapr.actor.runtime.failure_policy import ActorReminderFailurePolicy
2121

2222

2323
class ActorReminderData:

dapr/actor/runtime/actor.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
from typing import Any, Optional
1919

2020
from dapr.actor.id import ActorId
21-
from dapr.actor.runtime._failure_policy import ActorReminderFailurePolicy
2221
from dapr.actor.runtime._method_context import ActorMethodContext
2322
from dapr.actor.runtime._reminder_data import ActorReminderData
2423
from dapr.actor.runtime._timer_data import TIMER_CALLBACK, ActorTimerData
2524
from dapr.actor.runtime.context import ActorRuntimeContext
25+
from dapr.actor.runtime.failure_policy import ActorReminderFailurePolicy
2626
from dapr.actor.runtime.state_manager import ActorStateManager
2727

2828

@@ -132,8 +132,8 @@ async def register_reminder(
132132
due_time (datetime.timedelta): the amount of time to delay before invoking the reminder
133133
for the first time.
134134
period (Optional[datetime.timedelta]): the optional time interval between reminder
135-
invocations after the first invocation. If not set, the reminder is triggered
136-
only once at ``due_time``.
135+
invocations after the first invocation. If not set, the Dapr runtime behavior
136+
for one-off or non-periodic reminders applies.
137137
ttl (Optional[datetime.timedelta]): the optional time interval before the reminder
138138
stops firing. If not set, the Dapr runtime default behavior applies.
139139
failure_policy (Optional[ActorReminderFailurePolicy]): the optional policy for
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""
4+
Copyright 2026 The Dapr Authors
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
"""
15+
16+
from datetime import timedelta
17+
from typing import Any, Dict, Optional
18+
19+
20+
class ActorReminderFailurePolicy:
21+
"""Defines what happens when an actor reminder fails to trigger.
22+
23+
Use :meth:`drop_policy` to discard failed ticks without retrying, or
24+
:meth:`constant_policy` to retry at a fixed interval.
25+
26+
Attributes:
27+
drop: whether this is a drop (no-retry) policy.
28+
interval: the retry interval for a constant policy.
29+
max_retries: the maximum number of retries for a constant policy.
30+
"""
31+
32+
def __init__(
33+
self,
34+
*,
35+
drop: bool = False,
36+
interval: Optional[timedelta] = None,
37+
max_retries: Optional[int] = None,
38+
):
39+
"""Creates a new :class:`ActorReminderFailurePolicy` instance.
40+
41+
Args:
42+
drop (bool): if True, creates a drop policy that discards the reminder
43+
tick on failure without retrying. Cannot be combined with interval
44+
or max_retries.
45+
interval (datetime.timedelta): the retry interval for a constant policy.
46+
max_retries (int): the maximum number of retries for a constant policy.
47+
If not set, retries indefinitely.
48+
49+
Raises:
50+
ValueError: if drop is combined with interval or max_retries, or if
51+
neither drop=True nor at least one of interval/max_retries is provided.
52+
"""
53+
if drop and (interval is not None or max_retries is not None):
54+
raise ValueError('drop policy cannot be combined with interval or max_retries')
55+
if not drop and interval is None and max_retries is None:
56+
raise ValueError('specify either drop=True or at least one of interval or max_retries')
57+
self._drop = drop
58+
self._interval = interval
59+
self._max_retries = max_retries
60+
61+
@classmethod
62+
def drop_policy(cls) -> 'ActorReminderFailurePolicy':
63+
"""Returns a policy that drops the reminder tick on failure (no retry)."""
64+
return cls(drop=True)
65+
66+
@classmethod
67+
def constant_policy(
68+
cls,
69+
interval: Optional[timedelta] = None,
70+
max_retries: Optional[int] = None,
71+
) -> 'ActorReminderFailurePolicy':
72+
"""Returns a policy that retries at a constant interval on failure.
73+
74+
Args:
75+
interval (datetime.timedelta): the time between retry attempts.
76+
max_retries (int): the maximum number of retry attempts. If not set,
77+
retries indefinitely.
78+
"""
79+
return cls(interval=interval, max_retries=max_retries)
80+
81+
@property
82+
def drop(self) -> bool:
83+
"""Returns True if this is a drop policy."""
84+
return self._drop
85+
86+
@property
87+
def interval(self) -> Optional[timedelta]:
88+
"""Returns the retry interval for a constant policy."""
89+
return self._interval
90+
91+
@property
92+
def max_retries(self) -> Optional[int]:
93+
"""Returns the maximum retries for a constant policy."""
94+
return self._max_retries
95+
96+
def as_dict(self) -> Dict[str, Any]:
97+
"""Gets :class:`ActorReminderFailurePolicy` as a dict object."""
98+
if self._drop:
99+
return {'drop': {}}
100+
d: Dict[str, Any] = {}
101+
if self._interval is not None:
102+
d['interval'] = self._interval
103+
if self._max_retries is not None:
104+
d['maxRetries'] = self._max_retries
105+
return {'constant': d}

dapr/actor/runtime/mock_actor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
from typing import Any, Optional, TypeVar
1818

1919
from dapr.actor.id import ActorId
20-
from dapr.actor.runtime._failure_policy import ActorReminderFailurePolicy
2120
from dapr.actor.runtime._reminder_data import ActorReminderData
2221
from dapr.actor.runtime._timer_data import TIMER_CALLBACK, ActorTimerData
2322
from dapr.actor.runtime.actor import Actor
23+
from dapr.actor.runtime.failure_policy import ActorReminderFailurePolicy
2424
from dapr.actor.runtime.mock_state_manager import MockStateManager
2525

2626

tests/actor/test_actor.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
from unittest import mock
1919

2020
from dapr.actor.id import ActorId
21-
from dapr.actor.runtime._failure_policy import ActorReminderFailurePolicy
2221
from dapr.actor.runtime._type_information import ActorTypeInformation
2322
from dapr.actor.runtime.config import ActorRuntimeConfig
2423
from dapr.actor.runtime.context import ActorRuntimeContext
24+
from dapr.actor.runtime.failure_policy import ActorReminderFailurePolicy
2525
from dapr.actor.runtime.runtime import ActorRuntime
2626
from dapr.conf import settings
2727
from dapr.serializers import DefaultJSONSerializer
@@ -180,6 +180,37 @@ def test_register_reminder_with_failure_policy(self):
180180
b'{"reminderName":"test_reminder","dueTime":"0h0m1s0ms0\\u03bcs","period":"0h0m1s0ms0\\u03bcs","data":"cmVtaW5kZXJfbWVzc2FnZQ==","failurePolicy":{"drop":{}}}', # noqa E501
181181
)
182182

183+
@mock.patch(
184+
'tests.actor.fake_client.FakeDaprActorClient.register_reminder',
185+
new=_async_mock(return_value=b'"ok"'),
186+
)
187+
def test_register_reminder_with_constant_failure_policy(self):
188+
test_actor_id = ActorId('test_id')
189+
test_type_info = ActorTypeInformation.create(FakeSimpleReminderActor)
190+
test_client = FakeDaprActorClient
191+
ctx = ActorRuntimeContext(test_type_info, self._serializer, self._serializer, test_client)
192+
test_actor = FakeSimpleReminderActor(ctx, test_actor_id)
193+
194+
_run(
195+
test_actor.register_reminder(
196+
'test_reminder',
197+
b'reminder_message',
198+
timedelta(seconds=1),
199+
timedelta(seconds=1),
200+
failure_policy=ActorReminderFailurePolicy.constant_policy(
201+
interval=timedelta(seconds=2),
202+
max_retries=5,
203+
),
204+
)
205+
)
206+
test_client.register_reminder.mock.assert_called_once()
207+
test_client.register_reminder.mock.assert_called_with(
208+
'FakeSimpleReminderActor',
209+
'test_id',
210+
'test_reminder',
211+
b'{"reminderName":"test_reminder","dueTime":"0h0m1s0ms0\\u03bcs","period":"0h0m1s0ms0\\u03bcs","data":"cmVtaW5kZXJfbWVzc2FnZQ==","failurePolicy":{"constant":{"interval":"0h0m2s0ms0\\u03bcs","maxRetries":5}}}', # noqa E501
212+
)
213+
183214
@mock.patch(
184215
'tests.actor.fake_client.FakeDaprActorClient.register_timer',
185216
new=_async_mock(return_value=b'"ok"'),

tests/actor/test_failure_policy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import unittest
1717
from datetime import timedelta
1818

19-
from dapr.actor.runtime._failure_policy import ActorReminderFailurePolicy
19+
from dapr.actor.runtime.failure_policy import ActorReminderFailurePolicy
2020

2121

2222
class ActorReminderFailurePolicyTests(unittest.TestCase):

tests/actor/test_reminder_data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
import unittest
1717
from datetime import timedelta
1818

19-
from dapr.actor.runtime._failure_policy import ActorReminderFailurePolicy
2019
from dapr.actor.runtime._reminder_data import ActorReminderData
20+
from dapr.actor.runtime.failure_policy import ActorReminderFailurePolicy
2121

2222

2323
class ActorReminderTests(unittest.TestCase):

0 commit comments

Comments
 (0)