Example #1
0
    def __init__(self, ctx: ActorRuntimeContext):
        self._runtime_ctx = ctx
        self._message_serializer = self._runtime_ctx.message_serializer

        self._active_actors: Dict[str, Actor] = {}
        self._active_actors_lock = asyncio.Lock()

        self._dispatcher = ActorMethodDispatcher(ctx.actor_type_info)
        self._timer_method_context = ActorMethodContext.create_for_timer(TIMER_METHOD_NAME)
        self._reminder_method_context = ActorMethodContext.create_for_reminder(REMINDER_METHOD_NAME)
 def test_dispatch(self):
     dispatcher = ActorMethodDispatcher(self._testActorTypeInfo)
     actorInstance = FakeSimpleActor(self._fake_runtime_ctx, None)
     result = _run(dispatcher.dispatch(actorInstance, "ActorMethod", 10))
     self.assertEqual({'name': 'actor_method'}, result)
 def test_get_return_type(self):
     dispatcher = ActorMethodDispatcher(self._testActorTypeInfo)
     arg_names = dispatcher.get_return_type("ActorMethod")
     self.assertEqual(dict, arg_names)
 def test_get_arg_types(self):
     dispatcher = ActorMethodDispatcher(self._testActorTypeInfo)
     arg_names = dispatcher.get_arg_types("ActorMethod")
     self.assertEqual([int], arg_names)
Example #5
0
class ActorManager:
    """A Actor Manager manages actors of a specific actor type."""
    def __init__(self, ctx: ActorRuntimeContext):
        self._runtime_ctx = ctx
        self._message_serializer = self._runtime_ctx.message_serializer

        self._active_actors: Dict[str, Actor] = {}
        self._active_actors_lock = asyncio.Lock()

        self._dispatcher = ActorMethodDispatcher(ctx.actor_type_info)
        self._timer_method_context = ActorMethodContext.create_for_timer(
            TIMER_METHOD_NAME)
        self._reminder_method_context = ActorMethodContext.create_for_reminder(
            REMINDER_METHOD_NAME)

    async def activate_actor(self, actor_id: ActorId):
        """Activates actor."""
        actor = self._runtime_ctx.create_actor(actor_id)
        await actor._on_activate_internal()

        async with self._active_actors_lock:
            self._active_actors[actor_id.id] = actor

    async def deactivate_actor(self, actor_id: ActorId):
        async with self._active_actors_lock:
            deactivated_actor = self._active_actors.pop(actor_id.id, None)
            if not deactivated_actor:
                raise ValueError(f'{actor_id} is not activated')
        await deactivated_actor._on_deactivate_internal()

    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.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)

    async def fire_timer(self, actor_id: ActorId, timer_name: str) -> None:
        async def invoke_timer(actor: Actor) -> Optional[bytes]:
            await actor._fire_timer_internal(timer_name)
            return None

        await self._dispatch_internal(actor_id, self._reminder_method_context,
                                      invoke_timer)

    async def dispatch(self, actor_id: ActorId, actor_method_name: str,
                       request_body: bytes) -> bytes:
        method_context = ActorMethodContext.create_for_actor(actor_method_name)
        arg_types = self._dispatcher.get_arg_types(actor_method_name)

        async def invoke_method(actor):
            if len(arg_types) > 0:
                # Limitation:
                # * Support only one argument
                # * If you use the default DaprJSONSerializer, it support only object type
                # as a argument
                input_obj = self._message_serializer.deserialize(
                    request_body, arg_types[0])
                rtnval = await self._dispatcher.dispatch(
                    actor, actor_method_name, input_obj)
            else:
                rtnval = await self._dispatcher.dispatch(
                    actor, actor_method_name)
            return rtnval

        rtn_obj = await self._dispatch_internal(actor_id, method_context,
                                                invoke_method)
        return self._message_serializer.serialize(rtn_obj)

    async def _dispatch_internal(
        self, actor_id: ActorId, method_context: ActorMethodContext,
        dispatch_action: Callable[[Actor], Coroutine[Any, Any,
                                                     Optional[bytes]]]
    ) -> object:
        # Activate actor when actor is invoked.
        if actor_id.id not in self._active_actors:
            await self.activate_actor(actor_id)
        actor = None
        async with self._active_actors_lock:
            actor = self._active_actors.get(actor_id.id, None)
        if not actor:
            raise ValueError(f'{actor_id} is not activated')

        try:
            await actor._on_pre_actor_method_internal(method_context)
            retval = await dispatch_action(actor)
            await actor._on_post_actor_method_internal(method_context)
        except DaprInternalError as ex:
            await actor._on_invoke_failed_internal(ex)
            raise ex

        return retval