autogen/samples/apps/cap/py/autogencap/ActorConnector.py
Rajan db30ec8961
Reduce sleep() in CAP library code (#2189)
* 1) Removed most framework sleeps 2) refactored connection code

* pre-commit fixes

* pre-commit

* ignore protobuf files in pre-commit checks

* Fix duplicate actor registration

* refactor change

* Nicer printing of Actors

* 1) Report recv_multipart errors 4) Always send 4 parts

* AutoGen generate_reply expects to wait indefinitely for an answer.  CAP can wait a certain amount and give up.   In order to reconcile the two, AutoGenConnector is set to wait indefinitely.

* pre-commit formatting fixes

* pre-commit format changes

* don't check autogenerated proto py files
2024-04-02 07:49:07 +00:00

147 lines
5.7 KiB
Python

# Agent_Sender takes a zmq context, Topic and creates a
# socket that can publish to that topic. It exposes this functionality
# using send_msg method
import zmq
from zmq.utils.monitor import recv_monitor_message
import time
import uuid
from .DebugLog import Debug, Error, Info
from .Config import xsub_url, xpub_url, router_url
from typing import Any, Dict
class ActorSender:
def __init__(self, context, topic):
self._context = context
self._topic = topic
self._connect_pub_socket()
def _connect_pub_socket(self):
Debug("ActorSender", f"Connecting pub socket {self._topic}")
self._pub_socket = self._context.socket(zmq.PUB)
monitor = self._pub_socket.get_monitor_socket()
self._pub_socket.setsockopt(zmq.LINGER, 0)
self._pub_socket.connect(xsub_url)
# Monitor handshake on the pub socket
while monitor.poll():
evt: Dict[str, Any] = {}
mon_evt = recv_monitor_message(monitor)
evt.update(mon_evt)
if evt["event"] == zmq.EVENT_MONITOR_STOPPED or evt["event"] == zmq.EVENT_HANDSHAKE_SUCCEEDED:
Debug("ActorSender", "Handshake received (Or Monitor stopped)")
break
self._pub_socket.disable_monitor()
monitor.close()
self._send_recv_router_msg()
def _send_recv_router_msg(self):
# Send a request to the router and wait for a response
req_socket = self._context.socket(zmq.REQ)
req_socket.connect(router_url)
try:
Debug("ActorSender", "Broker Check Request Sent")
req_socket.send_string("Request")
_ = req_socket.recv_string()
Debug("ActorSender", "Broker Check Response Received")
finally:
req_socket.close()
def send_txt_msg(self, msg):
Debug("ActorSender", f"[{self._topic}] send_txt_msg: {msg}")
self._pub_socket.send_multipart(
[self._topic.encode("utf8"), "text".encode("utf8"), "no_resp".encode("utf8"), msg.encode("utf8")]
)
def send_bin_msg(self, msg_type: str, msg):
Debug("ActorSender", f"[{self._topic}] send_bin_msg: {msg_type}")
self._pub_socket.send_multipart(
[self._topic.encode("utf8"), msg_type.encode("utf8"), "no_resp".encode("utf8"), msg]
)
def send_bin_request_msg(self, msg_type: str, msg, resp_topic: str):
Debug("ActorSender", f"[{self._topic}] send_bin_request_msg: {msg_type}")
self._pub_socket.send_multipart(
[self._topic.encode("utf8"), msg_type.encode("utf8"), resp_topic.encode("utf8"), msg]
)
def close(self):
self._pub_socket.close()
class ActorConnector:
def __init__(self, context, topic):
self._context = context
self._topic = topic
self._connect_sub_socket()
self._sender = ActorSender(context, topic)
time.sleep(0.1) # Wait for the socket to connect
def _connect_sub_socket(self):
self._resp_socket = self._context.socket(zmq.SUB)
monitor = self._resp_socket.get_monitor_socket()
self._resp_socket.setsockopt(zmq.LINGER, 0)
self._resp_socket.setsockopt(zmq.RCVTIMEO, 250)
self._resp_socket.connect(xpub_url)
self._resp_topic = str(uuid.uuid4())
Debug("ActorConnector", f"subscribe to: {self._resp_topic}")
self._resp_socket.setsockopt_string(zmq.SUBSCRIBE, f"{self._resp_topic}")
while monitor.poll():
evt: Dict[str, Any] = {}
mon_evt = recv_monitor_message(monitor)
evt.update(mon_evt)
Debug("ActorConnector", evt)
if evt["event"] == zmq.EVENT_MONITOR_STOPPED or evt["event"] == zmq.EVENT_HANDSHAKE_SUCCEEDED:
Debug("ActorConnector", "Handshake received (Or Monitor stopped)")
break
self._resp_socket.disable_monitor()
monitor.close()
self._send_recv_router_msg()
def _send_recv_router_msg(self):
# Send a request to the router and wait for a response
req_socket = self._context.socket(zmq.REQ)
req_socket.connect(router_url)
try:
Debug("ActorConnector", "Broker Check Request Sent")
req_socket.send_string("Request")
_ = req_socket.recv_string()
Debug("ActorConnector", "Broker Check Response Received")
finally:
req_socket.close()
def send_txt_msg(self, msg):
self._sender.send_txt_msg(msg)
def send_bin_msg(self, msg_type: str, msg):
self._sender.send_bin_msg(msg_type, msg)
def binary_request(self, msg_type: str, msg, retry=5):
original_timeout: int = 0
if retry == -1:
original_timeout = self._resp_socket.getsockopt(zmq.RCVTIMEO)
self._resp_socket.setsockopt(zmq.RCVTIMEO, 1000)
try:
self._sender.send_bin_request_msg(msg_type, msg, self._resp_topic)
while retry == -1 or retry > 0:
try:
topic, resp_msg_type, _, resp = self._resp_socket.recv_multipart()
return topic, resp_msg_type, resp
except zmq.Again:
Debug(
"ActorConnector", f"{self._topic}: No response received. retry_count={retry}, max_retry={retry}"
)
time.sleep(0.01)
if retry != -1:
retry -= 1
finally:
if retry == -1:
self._resp_socket.setsockopt(zmq.RCVTIMEO, original_timeout)
Error("ActorConnector", f"{self._topic}: No response received. Giving up.")
return None, None, None
def close(self):
self._sender.close()
self._resp_socket.close()