Skip to content

Commit 7792948

Browse files
committed
BUGFIX:
- proxy decorator could not handle timeouts
1 parent 726156d commit 7792948

File tree

1 file changed

+55
-49
lines changed

1 file changed

+55
-49
lines changed

core/services/base.py

Lines changed: 55 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
logger = logging.getLogger(__name__)
3434

3535

36-
def proxy(original_function: Callable[..., Any] = None, *, timeout: float = 60):
36+
def proxy(_func: Callable[..., Any] | None = None, *, timeout: float = 60):
3737
"""
3838
Can be used as a decorator to any service method, that should act as a remote call, if the server provided
3939
is not on the same node.
@@ -44,54 +44,60 @@ async def my_fancy_method(self, server: Server, *args, **kwargs) -> Any:
4444
4545
This will call my_fancy_method on the remote node, if the server is remote, and on the local node, if it is not.
4646
"""
47-
48-
@wraps(original_function)
49-
async def wrapper(self, *args, **kwargs):
50-
signature = inspect.signature(original_function)
51-
bound_args = signature.bind(self, *args, **kwargs)
52-
bound_args.apply_defaults()
53-
arg_dict = {k: v for k, v in bound_args.arguments.items() if k != "self"}
54-
55-
# Dereference DataObject and Enum values in parameters
56-
params = {
57-
k: v.name if isinstance(v, DataObject)
58-
else v.value if isinstance(v, Enum)
59-
else v
60-
for k, v in arg_dict.items()
61-
if v is not None # Ignore None values
62-
}
63-
64-
call = {
65-
"command": "rpc",
66-
"service": self.__class__.__name__,
67-
"method": original_function.__name__,
68-
"params": params
69-
}
70-
71-
# Try to pick the node from the functions arguments
72-
node = None
73-
if arg_dict.get("server"):
74-
node = arg_dict["server"].node
75-
elif arg_dict.get("instance"):
76-
node = arg_dict["instance"].node
77-
elif arg_dict.get("node"):
78-
node = arg_dict["node"]
79-
80-
# Log an error if no valid object is found
81-
if node is None:
82-
raise ValueError(
83-
f"Cannot proxy function {original_function.__name__}: no valid reference object found in arguments. "
84-
f"Expected 'server', 'instance', or 'node' parameter with valid node reference.")
85-
86-
# If the node is remote, send the call synchronously
87-
if node.is_remote:
88-
data = await self.bus.send_to_node_sync(call, node=node.name, timeout=timeout)
89-
return data.get('return')
90-
91-
# Otherwise, call the original function directly
92-
return await original_function(self, *args, **kwargs)
93-
94-
return wrapper
47+
def decorator(original_function: Callable[..., Any]):
48+
@wraps(original_function)
49+
async def wrapper(self, *args, **kwargs):
50+
signature = inspect.signature(original_function)
51+
bound_args = signature.bind(self, *args, **kwargs)
52+
bound_args.apply_defaults()
53+
arg_dict = {k: v for k, v in bound_args.arguments.items() if k != "self"}
54+
55+
# Dereference DataObject and Enum values in parameters
56+
params = {
57+
k: v.name if isinstance(v, DataObject)
58+
else v.value if isinstance(v, Enum)
59+
else v
60+
for k, v in arg_dict.items()
61+
if v is not None # Ignore None values
62+
}
63+
64+
call = {
65+
"command": "rpc",
66+
"service": self.__class__.__name__,
67+
"method": original_function.__name__,
68+
"params": params
69+
}
70+
71+
# Try to pick the node from the functions arguments
72+
node = None
73+
if arg_dict.get("server"):
74+
node = arg_dict["server"].node
75+
elif arg_dict.get("instance"):
76+
node = arg_dict["instance"].node
77+
elif arg_dict.get("node"):
78+
node = arg_dict["node"]
79+
80+
# Log an error if no valid object is found
81+
if node is None:
82+
raise ValueError(
83+
f"Cannot proxy function {original_function.__name__}: no valid reference object found in arguments. "
84+
f"Expected 'server', 'instance', or 'node' parameter with valid node reference.")
85+
86+
# If the node is remote, send the call synchronously
87+
if node.is_remote:
88+
data = await self.bus.send_to_node_sync(call, node=node.name, timeout=timeout)
89+
return data.get('return')
90+
91+
# Otherwise, call the original function directly
92+
return await original_function(self, *args, **kwargs)
93+
return wrapper
94+
95+
# If used as @proxy(timeout=nn)
96+
if _func is None:
97+
return decorator
98+
99+
# If used as @proxy without parentheses
100+
return decorator(_func)
95101

96102

97103
class Service(ABC):

0 commit comments

Comments
 (0)