async def register_reminder(self, name: str, state: bytes, due_time: timedelta, period: timedelta) -> None: """Registers actor reminder. Reminders are a mechanism to trigger persistent callbacks on an actor at specified times. Their functionality is similar to timers. But unlike timers, reminders are triggered under all circumstances until the actor explicitly unregisters them or the actor is explicitly deleted. Specifically, reminders are triggered across actor deactivations and failovers because the Actors runtime persists information about the actor's reminders using actor state provider. Also existing reminders can be updated by calling this registration method again using the same reminderName. Args: name (str): the name of the reminder to register. the name must be unique per actor. state (bytes): the user state passed to the reminder invocation. due_time (datetime.timedelta): the amount of time to delay before invoking the reminder for the first time. period (datetime.timedelta): the time interval between reminder invocations after the first invocation. """ reminder = ActorReminderData(name, state, due_time, period) req_body = self._runtime_ctx.message_serializer.serialize( reminder.as_dict()) await self._runtime_ctx.dapr_client.register_reminder( self._runtime_ctx.actor_type_info.type_name, self.id.id, name, req_body)
def test_as_dict(self): reminder = ActorReminderData('test_reminder', b'reminder_state', timedelta(seconds=1), timedelta(seconds=1)) expected = { 'reminderName': 'test_reminder', 'dueTime': timedelta(seconds=1), 'period': timedelta(seconds=1), 'data': 'cmVtaW5kZXJfc3RhdGU=', } self.assertDictEqual(expected, reminder.as_dict())
def test_invalid_state(self): with self.assertRaises(ValueError): ActorReminderData( 'test_reminder', 123, # int type timedelta(seconds=1), timedelta(seconds=1)) ActorReminderData( 'test_reminder', 'reminder_state', # string type timedelta(seconds=1), timedelta(seconds=1))
def test_valid_state(self): # bytes type state data reminder = ActorReminderData('test_reminder', b'reminder_state', timedelta(seconds=1), timedelta(seconds=2), timedelta(seconds=3)) self.assertEqual(b'reminder_state', reminder.state)
def test_from_dict(self): reminder = ActorReminderData.from_dict( 'test_reminder', { 'dueTime': timedelta(seconds=1), 'period': timedelta(seconds=1), 'data': 'cmVtaW5kZXJfc3RhdGU=', }) self.assertEqual('test_reminder', reminder.reminder_name) self.assertEqual(timedelta(seconds=1), reminder.due_time) self.assertEqual(timedelta(seconds=1), reminder.period) self.assertEqual(b'reminder_state', reminder.state)
async def fire_reminder( self, actor_id: ActorId, reminder_name: str, request_body: bytes) -> None: if not self._runtime_ctx.actor_type_info.is_remindable(): raise ValueError( f'{self._runtime_ctx.actor_type_info.type_name} does not implment Remindable.') request_obj = self._message_serializer.deserialize(request_body, object) if isinstance(request_obj, dict): reminder_data = ActorReminderData.from_dict(reminder_name, request_obj) # ignore if request_obj is not dict async def invoke_reminder(actor: Actor) -> Optional[bytes]: reminder = getattr(actor, REMINDER_METHOD_NAME) if reminder is not None: await reminder(reminder_data.reminder_name, reminder_data.state, reminder_data.due_time, reminder_data.period) return None await self._dispatch_internal(actor_id, self._reminder_method_context, invoke_reminder)