mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-27 01:16:22 +02:00
* Plugin architecture for messaging fabric * Schemas use a technology neutral expression * Schemas strictness has uncovered some incorrect schema use which is fixed
91 lines
2.6 KiB
Python
91 lines
2.6 KiB
Python
|
|
import asyncio
|
|
import queue
|
|
import uuid
|
|
import logging
|
|
|
|
from ... schema import EntityContexts
|
|
from ... base import Subscriber
|
|
|
|
from . serialize import serialize_entity_contexts
|
|
|
|
# Module logger
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class EntityContextsExport:
|
|
|
|
def __init__(
|
|
self, ws, running, backend, queue, consumer, subscriber
|
|
):
|
|
|
|
self.ws = ws
|
|
self.running = running
|
|
self.backend = backend
|
|
self.queue = queue
|
|
self.consumer = consumer
|
|
self.subscriber = subscriber
|
|
|
|
async def destroy(self):
|
|
# Step 1: Signal stop to prevent new messages
|
|
self.running.stop()
|
|
|
|
# Step 2: Wait briefly for in-flight messages
|
|
await asyncio.sleep(0.5)
|
|
|
|
# Step 3: Unsubscribe and stop subscriber (triggers queue drain)
|
|
if hasattr(self, 'subs'):
|
|
await self.subs.unsubscribe_all(self.id)
|
|
await self.subs.stop()
|
|
|
|
# Step 4: Close websocket last
|
|
if self.ws and not self.ws.closed:
|
|
await self.ws.close()
|
|
|
|
async def receive(self, msg):
|
|
# Ignore incoming info from websocket
|
|
pass
|
|
|
|
async def run(self):
|
|
"""Enhanced run with better error handling"""
|
|
self.subs = Subscriber(
|
|
backend = self.backend,
|
|
topic = self.queue,
|
|
consumer_name = self.consumer,
|
|
subscription = self.subscriber,
|
|
schema = EntityContexts,
|
|
backpressure_strategy = "block" # Configurable
|
|
)
|
|
|
|
await self.subs.start()
|
|
|
|
self.id = str(uuid.uuid4())
|
|
q = await self.subs.subscribe_all(self.id)
|
|
|
|
consecutive_errors = 0
|
|
max_consecutive_errors = 5
|
|
|
|
while self.running.get():
|
|
try:
|
|
resp = await asyncio.wait_for(q.get(), timeout=0.5)
|
|
await self.ws.send_json(serialize_entity_contexts(resp))
|
|
consecutive_errors = 0 # Reset on success
|
|
|
|
except asyncio.TimeoutError:
|
|
continue
|
|
|
|
except queue.Empty:
|
|
continue
|
|
|
|
except Exception as e:
|
|
logger.error(f"Exception sending to websocket: {str(e)}")
|
|
consecutive_errors += 1
|
|
|
|
if consecutive_errors >= max_consecutive_errors:
|
|
logger.error("Too many consecutive errors, shutting down")
|
|
break
|
|
|
|
# Brief pause before retry
|
|
await asyncio.sleep(0.1)
|
|
|
|
# Graceful cleanup handled in destroy()
|
|
|