refactor: half way to process per session
All checks were successful
Build Worker Base and Application Images / check-base-changes (push) Successful in 7s
Build Worker Base and Application Images / build-base (push) Has been skipped
Build Worker Base and Application Images / build-docker (push) Successful in 2m52s
Build Worker Base and Application Images / deploy-stack (push) Successful in 9s
All checks were successful
Build Worker Base and Application Images / check-base-changes (push) Successful in 7s
Build Worker Base and Application Images / build-base (push) Has been skipped
Build Worker Base and Application Images / build-docker (push) Successful in 2m52s
Build Worker Base and Application Images / deploy-stack (push) Successful in 9s
This commit is contained in:
parent
2e5316ca01
commit
34d1982e9e
12 changed files with 2771 additions and 92 deletions
317
core/processes/communication.py
Normal file
317
core/processes/communication.py
Normal file
|
@ -0,0 +1,317 @@
|
|||
"""
|
||||
Inter-Process Communication (IPC) system for session processes.
|
||||
Defines message types and protocols for main ↔ session communication.
|
||||
"""
|
||||
|
||||
import time
|
||||
from enum import Enum
|
||||
from typing import Dict, Any, Optional, Union
|
||||
from dataclasses import dataclass, field
|
||||
import numpy as np
|
||||
|
||||
|
||||
class MessageType(Enum):
|
||||
"""Message types for IPC communication."""
|
||||
|
||||
# Commands: Main → Session
|
||||
INITIALIZE = "initialize"
|
||||
PROCESS_FRAME = "process_frame"
|
||||
SET_SESSION_ID = "set_session_id"
|
||||
SHUTDOWN = "shutdown"
|
||||
HEALTH_CHECK = "health_check"
|
||||
|
||||
# Responses: Session → Main
|
||||
INITIALIZED = "initialized"
|
||||
DETECTION_RESULT = "detection_result"
|
||||
SESSION_SET = "session_set"
|
||||
SHUTDOWN_COMPLETE = "shutdown_complete"
|
||||
HEALTH_RESPONSE = "health_response"
|
||||
ERROR = "error"
|
||||
|
||||
|
||||
@dataclass
|
||||
class IPCMessage:
|
||||
"""Base class for all IPC messages."""
|
||||
type: MessageType
|
||||
session_id: str
|
||||
timestamp: float = field(default_factory=time.time)
|
||||
message_id: str = field(default_factory=lambda: str(int(time.time() * 1000000)))
|
||||
|
||||
|
||||
@dataclass
|
||||
class InitializeCommand(IPCMessage):
|
||||
"""Initialize session process with configuration."""
|
||||
subscription_config: Dict[str, Any] = field(default_factory=dict)
|
||||
model_config: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProcessFrameCommand(IPCMessage):
|
||||
"""Process a frame through the detection pipeline."""
|
||||
frame: Optional[np.ndarray] = None
|
||||
display_id: str = ""
|
||||
subscription_identifier: str = ""
|
||||
frame_timestamp: float = 0.0
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class SetSessionIdCommand(IPCMessage):
|
||||
"""Set the session ID for the current session."""
|
||||
backend_session_id: str = ""
|
||||
display_id: str = ""
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class ShutdownCommand(IPCMessage):
|
||||
"""Shutdown the session process gracefully."""
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class HealthCheckCommand(IPCMessage):
|
||||
"""Check health status of session process."""
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class InitializedResponse(IPCMessage):
|
||||
"""Response indicating successful initialization."""
|
||||
success: bool = False
|
||||
error_message: Optional[str] = None
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class DetectionResultResponse(IPCMessage):
|
||||
"""Detection results from session process."""
|
||||
detections: Dict[str, Any] = field(default_factory=dict)
|
||||
processing_time: float = 0.0
|
||||
phase: str = "" # "detection" or "processing"
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class SessionSetResponse(IPCMessage):
|
||||
"""Response confirming session ID was set."""
|
||||
success: bool = False
|
||||
backend_session_id: str = ""
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class ShutdownCompleteResponse(IPCMessage):
|
||||
"""Response confirming graceful shutdown."""
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class HealthResponse(IPCMessage):
|
||||
"""Health status response."""
|
||||
status: str = "unknown" # "healthy", "degraded", "unhealthy"
|
||||
memory_usage_mb: float = 0.0
|
||||
cpu_percent: float = 0.0
|
||||
gpu_memory_mb: Optional[float] = None
|
||||
uptime_seconds: float = 0.0
|
||||
processed_frames: int = 0
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class ErrorResponse(IPCMessage):
|
||||
"""Error message from session process."""
|
||||
error_type: str = ""
|
||||
error_message: str = ""
|
||||
traceback: Optional[str] = None
|
||||
|
||||
|
||||
|
||||
# Type aliases for message unions
|
||||
CommandMessage = Union[
|
||||
InitializeCommand,
|
||||
ProcessFrameCommand,
|
||||
SetSessionIdCommand,
|
||||
ShutdownCommand,
|
||||
HealthCheckCommand
|
||||
]
|
||||
|
||||
ResponseMessage = Union[
|
||||
InitializedResponse,
|
||||
DetectionResultResponse,
|
||||
SessionSetResponse,
|
||||
ShutdownCompleteResponse,
|
||||
HealthResponse,
|
||||
ErrorResponse
|
||||
]
|
||||
|
||||
IPCMessageUnion = Union[CommandMessage, ResponseMessage]
|
||||
|
||||
|
||||
class MessageSerializer:
|
||||
"""Handles serialization/deserialization of IPC messages."""
|
||||
|
||||
@staticmethod
|
||||
def serialize_message(message: IPCMessageUnion) -> Dict[str, Any]:
|
||||
"""
|
||||
Serialize message to dictionary for queue transport.
|
||||
|
||||
Args:
|
||||
message: Message to serialize
|
||||
|
||||
Returns:
|
||||
Dictionary representation of message
|
||||
"""
|
||||
result = {
|
||||
'type': message.type.value,
|
||||
'session_id': message.session_id,
|
||||
'timestamp': message.timestamp,
|
||||
'message_id': message.message_id,
|
||||
}
|
||||
|
||||
# Add specific fields based on message type
|
||||
if isinstance(message, InitializeCommand):
|
||||
result.update({
|
||||
'subscription_config': message.subscription_config,
|
||||
'model_config': message.model_config
|
||||
})
|
||||
elif isinstance(message, ProcessFrameCommand):
|
||||
result.update({
|
||||
'frame': message.frame,
|
||||
'display_id': message.display_id,
|
||||
'subscription_identifier': message.subscription_identifier,
|
||||
'frame_timestamp': message.frame_timestamp
|
||||
})
|
||||
elif isinstance(message, SetSessionIdCommand):
|
||||
result.update({
|
||||
'backend_session_id': message.backend_session_id,
|
||||
'display_id': message.display_id
|
||||
})
|
||||
elif isinstance(message, InitializedResponse):
|
||||
result.update({
|
||||
'success': message.success,
|
||||
'error_message': message.error_message
|
||||
})
|
||||
elif isinstance(message, DetectionResultResponse):
|
||||
result.update({
|
||||
'detections': message.detections,
|
||||
'processing_time': message.processing_time,
|
||||
'phase': message.phase
|
||||
})
|
||||
elif isinstance(message, SessionSetResponse):
|
||||
result.update({
|
||||
'success': message.success,
|
||||
'backend_session_id': message.backend_session_id
|
||||
})
|
||||
elif isinstance(message, HealthResponse):
|
||||
result.update({
|
||||
'status': message.status,
|
||||
'memory_usage_mb': message.memory_usage_mb,
|
||||
'cpu_percent': message.cpu_percent,
|
||||
'gpu_memory_mb': message.gpu_memory_mb,
|
||||
'uptime_seconds': message.uptime_seconds,
|
||||
'processed_frames': message.processed_frames
|
||||
})
|
||||
elif isinstance(message, ErrorResponse):
|
||||
result.update({
|
||||
'error_type': message.error_type,
|
||||
'error_message': message.error_message,
|
||||
'traceback': message.traceback
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def deserialize_message(data: Dict[str, Any]) -> IPCMessageUnion:
|
||||
"""
|
||||
Deserialize dictionary back to message object.
|
||||
|
||||
Args:
|
||||
data: Dictionary representation
|
||||
|
||||
Returns:
|
||||
Deserialized message object
|
||||
"""
|
||||
msg_type = MessageType(data['type'])
|
||||
session_id = data['session_id']
|
||||
timestamp = data['timestamp']
|
||||
message_id = data['message_id']
|
||||
|
||||
base_kwargs = {
|
||||
'session_id': session_id,
|
||||
'timestamp': timestamp,
|
||||
'message_id': message_id
|
||||
}
|
||||
|
||||
if msg_type == MessageType.INITIALIZE:
|
||||
return InitializeCommand(
|
||||
type=msg_type,
|
||||
subscription_config=data['subscription_config'],
|
||||
model_config=data['model_config'],
|
||||
**base_kwargs
|
||||
)
|
||||
elif msg_type == MessageType.PROCESS_FRAME:
|
||||
return ProcessFrameCommand(
|
||||
type=msg_type,
|
||||
frame=data['frame'],
|
||||
display_id=data['display_id'],
|
||||
subscription_identifier=data['subscription_identifier'],
|
||||
frame_timestamp=data['frame_timestamp'],
|
||||
**base_kwargs
|
||||
)
|
||||
elif msg_type == MessageType.SET_SESSION_ID:
|
||||
return SetSessionIdCommand(
|
||||
backend_session_id=data['backend_session_id'],
|
||||
display_id=data['display_id'],
|
||||
**base_kwargs
|
||||
)
|
||||
elif msg_type == MessageType.SHUTDOWN:
|
||||
return ShutdownCommand(**base_kwargs)
|
||||
elif msg_type == MessageType.HEALTH_CHECK:
|
||||
return HealthCheckCommand(**base_kwargs)
|
||||
elif msg_type == MessageType.INITIALIZED:
|
||||
return InitializedResponse(
|
||||
type=msg_type,
|
||||
success=data['success'],
|
||||
error_message=data.get('error_message'),
|
||||
**base_kwargs
|
||||
)
|
||||
elif msg_type == MessageType.DETECTION_RESULT:
|
||||
return DetectionResultResponse(
|
||||
type=msg_type,
|
||||
detections=data['detections'],
|
||||
processing_time=data['processing_time'],
|
||||
phase=data['phase'],
|
||||
**base_kwargs
|
||||
)
|
||||
elif msg_type == MessageType.SESSION_SET:
|
||||
return SessionSetResponse(
|
||||
type=msg_type,
|
||||
success=data['success'],
|
||||
backend_session_id=data['backend_session_id'],
|
||||
**base_kwargs
|
||||
)
|
||||
elif msg_type == MessageType.SHUTDOWN_COMPLETE:
|
||||
return ShutdownCompleteResponse(type=msg_type, **base_kwargs)
|
||||
elif msg_type == MessageType.HEALTH_RESPONSE:
|
||||
return HealthResponse(
|
||||
type=msg_type,
|
||||
status=data['status'],
|
||||
memory_usage_mb=data['memory_usage_mb'],
|
||||
cpu_percent=data['cpu_percent'],
|
||||
gpu_memory_mb=data.get('gpu_memory_mb'),
|
||||
uptime_seconds=data.get('uptime_seconds', 0.0),
|
||||
processed_frames=data.get('processed_frames', 0),
|
||||
**base_kwargs
|
||||
)
|
||||
elif msg_type == MessageType.ERROR:
|
||||
return ErrorResponse(
|
||||
type=msg_type,
|
||||
error_type=data['error_type'],
|
||||
error_message=data['error_message'],
|
||||
traceback=data.get('traceback'),
|
||||
**base_kwargs
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"Unknown message type: {msg_type}")
|
Loading…
Add table
Add a link
Reference in a new issue