Skip to content

Commit ce437a1

Browse files
committed
Correct Actor register function
1 parent 6a18d3d commit ce437a1

5 files changed

Lines changed: 184 additions & 72 deletions

File tree

example/joe.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from spawn.eigr.functions.actors.api.workflows.effect import Effect
1414

1515

16-
actor = Actor(settings=ActorSettings(name="joe", stateful=False))
16+
actor = Actor(settings=ActorSettings(name="joe", stateful=True))
1717

1818

1919
@actor.action("setLanguage")
@@ -25,3 +25,14 @@ def set_language(request: Request, ctx: Context) -> Value:
2525
.metada(Metadata())\
2626
.state({})\
2727
.reply()
28+
29+
30+
@actor.timer_action(every=1000)
31+
def hi(request: Request, ctx: Context) -> Value:
32+
return Value()\
33+
.of("test")\
34+
.broadcast(Broadcast())\
35+
.effect(Effect())\
36+
.metada(Metadata())\
37+
.state({})\
38+
.reply()

example/spawn_example.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@
1111
request.language = "erlang"
1212

1313
spawn = Spawn()
14-
spawn.port("9003").register_actor(joe_actor).start()
14+
spawn.port(8091).proxy_port(9003).actor_system(
15+
"spawn-system").add_actor(joe_actor).start()
1516
# spawn.invoke("vijay", "setLanguage", request, Reply)

spawn/eigr/functions/actors/api/actor.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,59 @@
88
from spawn.eigr.functions.actors.api.settings import ActorSettings
99

1010

11+
@dataclass
12+
class TimerFunction:
13+
every: int
14+
action: Callable
15+
16+
1117
@dataclass
1218
class Actor:
1319
settings: ActorSettings
1420

1521
action_handlers: MutableMapping[str,
1622
Callable] = field(default_factory=dict)
1723

24+
timer_action_handlers: MutableMapping[str,
25+
Callable] = field(default_factory=dict)
26+
1827
def action(self, name: str):
1928
def register_action_handler(function):
2029
"""
2130
Register the function to handle actions
2231
"""
23-
if name in self.action_handlers:
32+
action_name = name if name is not None else function.__name__
33+
34+
if action_name in self.action_handlers:
2435
raise Exception("Action handler function {} already defined for action {}".format(
25-
self.action_handlers[name], name))
36+
self.action_handlers[action_name], action_name))
2637
if function.__code__.co_argcount > 2:
2738
raise Exception(
2839
"At most two parameters, the input parameter and the context parameter, should be accepted by the action function")
29-
self.action_handlers[name] = function
40+
self.action_handlers[action_name] = function
3041
return function
3142

3243
return register_action_handler
3344

45+
def timer_action(self, every: int, name: str = None):
46+
def register_timer_action_handler(function):
47+
"""
48+
Register the function to handle actions
49+
"""
50+
action_name = name if name is not None else function.__name__
51+
52+
if name in self.timer_action_handlers:
53+
raise Exception("Timer Action handler function {} already defined for action {}".format(
54+
self.timer_action_handlers[action_name], action_name))
55+
if function.__code__.co_argcount > 2:
56+
raise Exception(
57+
"At most two parameters, the input parameter and the context parameter, should be accepted by the action function")
58+
self.timer_action_handlers[action_name] = TimerFunction(
59+
every=every, action=function)
60+
return function
61+
62+
return register_timer_action_handler
63+
3464

3565
def invoke(function, parameters):
3666
ordered_parameters = []

spawn/eigr/functions/actors/api/sdk.py

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
from flask import Flask, request, send_file
66

77
from dataclasses import dataclass, field
8-
from typing import List
8+
from typing import MutableMapping
99

1010
from spawn.eigr.functions.actors.api.actor import Actor
1111
from spawn.eigr.functions.actors.internal.controller import ActorController
1212

13-
from spawn.eigr.functions.protocol.actors.protocol_pb2 import ActorInvocation, ActorInvocationResponse, Context
1413
from google.protobuf.any_pb2 import Any as ProtoAny
1514

1615
import io
@@ -27,20 +26,7 @@ def action():
2726
data = request.data
2827
logging.info('Received Actor action request: %s', data)
2928

30-
# Decode request payload data here and call python real actors methods.
31-
databytes = bytes(data)
32-
actor_invocation = ActorInvocation()
33-
actor_invocation.ParseFromString(databytes)
34-
logging.debug('Actor invocation data: %s', actor_invocation)
35-
36-
# Update Context
37-
updated_context = Context()
38-
39-
# Then send ActorInvocationResponse back to the caller
40-
actor_invocation_response = ActorInvocationResponse()
41-
actor_invocation_response.actor_name = actor_invocation.actor_name
42-
actor_invocation_response.actor_system = actor_invocation.actor_system
43-
actor_invocation_response.updated_context.CopyFrom(updated_context)
29+
actor_invocation_response = controller.handle_invoke(data)
4430

4531
return send_file(
4632
io.BytesIO(actor_invocation_response.SerializeToString()),
@@ -60,9 +46,13 @@ class Spawn:
6046

6147
__app = None
6248
__controller = None
63-
__host = os.environ.get("HOST", "0.0.0.0")
64-
__port = os.environ.get("PORT", "8091")
65-
__actor_entities: List[Actor] = field(default_factory=list)
49+
__host = os.environ.get("USER_FUNCTION_HOST", "0.0.0.0")
50+
__port = os.environ.get("USER_FUNCTION_PORT", "8091")
51+
__proxy_host = os.environ.get("PROXY_HTTP_HOST", "0.0.0.0")
52+
__proxy_port = os.environ.get("PROXY_HTTP_PORT", "9001")
53+
__system: str = None
54+
__actor_entities: MutableMapping[str,
55+
Actor] = field(default_factory=dict)
6656

6757
# @staticmethod
6858
# def invoke(name: str, command: str, arg: Any, output_type: Any) -> Any:
@@ -77,21 +67,39 @@ def host(self, address: str):
7767
self.__host = address
7868
return self
7969

80-
def port(self, port: str):
70+
def port(self, port: int):
8171
"""Set the Network Port address."""
82-
self.__port = port
72+
self.__port = str(port)
8373
return self
8474

85-
def register_actor(self, actor: Actor):
75+
def proxy_host(self, host: str):
76+
"""Set the Spawn Proxy Host Address"""
77+
self.__proxy_host = host
78+
return self
79+
80+
def proxy_port(self, port: int):
81+
self.__proxy_port = str(port)
82+
return self
83+
84+
def actor_system(self, system: str = None):
85+
"""Set the ActorSystem"""
86+
self.__system = system
87+
return self
88+
89+
def add_actor(self, actor: Actor):
8690
"""Registry the user Actor entity."""
87-
self.__actor_entities.append(actor)
91+
self.__actor_entities[actor.settings.name] = actor
8892
return self
8993

9094
def start(self):
9195
"""Start the user function and HTTP Server."""
96+
if not self.__system:
97+
raise Exception(
98+
"ActorSystem cannot be None. Use actor_system function to set an ActorSystem")
99+
92100
address = "{}:{}".format(self.__host, self.__port)
93101
self.__controller = ActorController(
94-
self.__host, self.__port, self.__actor_entities)
102+
self.__proxy_host, self.__proxy_port, self.__system, self.__actor_entities)
95103

96104
self.__app = create_app(controller=self.__controller)
97105

0 commit comments

Comments
 (0)