Use zmq for inter process communication (#9309)

* Use zmq for inter process communication

* Use localhost for reply and request

* Use pyobj instead of json and Need to use separate requestors for each audio listener

* Cleanup port defining
This commit is contained in:
Nicolas Mowen
2024-02-14 17:24:36 -07:00
committed by GitHub
parent 198dbbdff1
commit dd3dc7949a
13 changed files with 116 additions and 91 deletions

View File

@@ -1,16 +1,25 @@
"""Facilitates communication between processes."""
import multiprocessing as mp
import queue
import os
import threading
from multiprocessing import Queue
from multiprocessing.synchronize import Event as MpEvent
from typing import Callable
import zmq
from frigate.comms.dispatcher import Communicator
from frigate.const import PORT_INTER_PROCESS_COMM
class InterProcessCommunicator(Communicator):
def __init__(self, queue: Queue) -> None:
self.queue = queue
def __init__(self) -> None:
INTER_PROCESS_COMM_PORT = (
os.environ.get("INTER_PROCESS_COMM_PORT") or PORT_INTER_PROCESS_COMM
)
self.context = zmq.Context()
self.socket = self.context.socket(zmq.REP)
self.socket.bind(f"tcp://127.0.0.1:{INTER_PROCESS_COMM_PORT}")
self.stop_event: MpEvent = mp.Event()
def publish(self, topic: str, payload: str, retain: bool) -> None:
@@ -23,17 +32,41 @@ class InterProcessCommunicator(Communicator):
self.reader_thread.start()
def read(self) -> None:
while not self.stop_event.is_set():
try:
(
topic,
value,
) = self.queue.get(True, 1)
except queue.Empty:
continue
while not self.stop_event.wait(0.5):
while True: # load all messages that are queued
try:
(topic, value) = self.socket.recv_pyobj(flags=zmq.NOBLOCK)
self._dispatcher(topic, value)
response = self._dispatcher(topic, value)
if response is not None:
self.socket.send_pyobj(response)
else:
self.socket.send_pyobj([])
except zmq.ZMQError:
break
def stop(self) -> None:
self.stop_event.set()
self.reader_thread.join()
self.socket.close()
self.context.destroy()
class InterProcessRequestor:
"""Simplifies sending data to InterProcessCommunicator and getting a reply."""
def __init__(self) -> None:
port = os.environ.get("INTER_PROCESS_COMM_PORT") or PORT_INTER_PROCESS_COMM
self.context = zmq.Context()
self.socket = self.context.socket(zmq.REQ)
self.socket.connect(f"tcp://127.0.0.1:{port}")
def send_data(self, topic: str, data: any) -> any:
"""Sends data and then waits for reply."""
self.socket.send_pyobj((topic, data))
return self.socket.recv_pyobj()
def stop(self) -> None:
self.socket.close()
self.context.destroy()