claude-mpm 4.1.4__py3-none-any.whl → 4.1.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/templates/research.json +39 -13
- claude_mpm/cli/__init__.py +2 -0
- claude_mpm/cli/commands/__init__.py +2 -0
- claude_mpm/cli/commands/configure.py +1221 -0
- claude_mpm/cli/commands/configure_tui.py +1921 -0
- claude_mpm/cli/commands/tickets.py +365 -784
- claude_mpm/cli/parsers/base_parser.py +7 -0
- claude_mpm/cli/parsers/configure_parser.py +119 -0
- claude_mpm/cli/startup_logging.py +39 -12
- claude_mpm/constants.py +1 -0
- claude_mpm/core/output_style_manager.py +24 -0
- claude_mpm/core/socketio_pool.py +35 -3
- claude_mpm/core/unified_agent_registry.py +46 -15
- claude_mpm/dashboard/static/css/connection-status.css +370 -0
- claude_mpm/dashboard/static/js/components/connection-debug.js +654 -0
- claude_mpm/dashboard/static/js/connection-manager.js +536 -0
- claude_mpm/dashboard/templates/index.html +11 -0
- claude_mpm/hooks/claude_hooks/services/__init__.py +3 -1
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +190 -0
- claude_mpm/services/agents/deployment/agent_discovery_service.py +12 -3
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +172 -233
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +575 -0
- claude_mpm/services/agents/deployment/agent_operation_service.py +573 -0
- claude_mpm/services/agents/deployment/agent_record_service.py +419 -0
- claude_mpm/services/agents/deployment/agent_state_service.py +381 -0
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +4 -2
- claude_mpm/services/diagnostics/checks/__init__.py +2 -0
- claude_mpm/services/diagnostics/checks/instructions_check.py +418 -0
- claude_mpm/services/diagnostics/diagnostic_runner.py +15 -2
- claude_mpm/services/event_bus/direct_relay.py +173 -0
- claude_mpm/services/infrastructure/__init__.py +31 -5
- claude_mpm/services/infrastructure/monitoring/__init__.py +43 -0
- claude_mpm/services/infrastructure/monitoring/aggregator.py +437 -0
- claude_mpm/services/infrastructure/monitoring/base.py +130 -0
- claude_mpm/services/infrastructure/monitoring/legacy.py +203 -0
- claude_mpm/services/infrastructure/monitoring/network.py +218 -0
- claude_mpm/services/infrastructure/monitoring/process.py +342 -0
- claude_mpm/services/infrastructure/monitoring/resources.py +243 -0
- claude_mpm/services/infrastructure/monitoring/service.py +367 -0
- claude_mpm/services/infrastructure/monitoring.py +67 -1030
- claude_mpm/services/project/analyzer.py +13 -4
- claude_mpm/services/project/analyzer_refactored.py +450 -0
- claude_mpm/services/project/analyzer_v2.py +566 -0
- claude_mpm/services/project/architecture_analyzer.py +461 -0
- claude_mpm/services/project/dependency_analyzer.py +462 -0
- claude_mpm/services/project/language_analyzer.py +265 -0
- claude_mpm/services/project/metrics_collector.py +410 -0
- claude_mpm/services/socketio/handlers/connection_handler.py +345 -0
- claude_mpm/services/socketio/server/broadcaster.py +32 -1
- claude_mpm/services/socketio/server/connection_manager.py +516 -0
- claude_mpm/services/socketio/server/core.py +63 -0
- claude_mpm/services/socketio/server/eventbus_integration.py +20 -9
- claude_mpm/services/socketio/server/main.py +27 -1
- claude_mpm/services/ticket_manager.py +5 -1
- claude_mpm/services/ticket_services/__init__.py +26 -0
- claude_mpm/services/ticket_services/crud_service.py +328 -0
- claude_mpm/services/ticket_services/formatter_service.py +290 -0
- claude_mpm/services/ticket_services/search_service.py +324 -0
- claude_mpm/services/ticket_services/validation_service.py +303 -0
- claude_mpm/services/ticket_services/workflow_service.py +244 -0
- {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/METADATA +3 -1
- {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/RECORD +67 -46
- claude_mpm/agents/OUTPUT_STYLE.md +0 -73
- claude_mpm/agents/backups/INSTRUCTIONS.md +0 -352
- claude_mpm/agents/templates/OPTIMIZATION_REPORT.md +0 -156
- claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +0 -79
- claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +0 -68
- claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +0 -77
- claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +0 -78
- claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +0 -67
- claude_mpm/agents/templates/backup/research_agent_2025011_234551.json +0 -88
- claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +0 -72
- claude_mpm/agents/templates/backup/research_memory_efficient.json +0 -88
- claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +0 -78
- claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +0 -62
- claude_mpm/agents/templates/vercel_ops_instructions.md +0 -582
- {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Enhanced Connection Event Handler for Socket.IO.
|
|
3
|
+
|
|
4
|
+
WHY: This module provides robust connection handling with state tracking,
|
|
5
|
+
event replay on reconnection, and health monitoring integration.
|
|
6
|
+
|
|
7
|
+
DESIGN DECISION: Centralized connection event handling ensures consistent
|
|
8
|
+
state management and provides resilient event delivery across reconnections.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
from .base import BaseEventHandler
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class EnhancedConnectionEventHandler(BaseEventHandler):
|
|
17
|
+
"""
|
|
18
|
+
Handles Socket.IO connection events with enhanced robustness.
|
|
19
|
+
|
|
20
|
+
Features:
|
|
21
|
+
- Persistent client tracking across reconnections
|
|
22
|
+
- Event replay on reconnection
|
|
23
|
+
- Connection health monitoring
|
|
24
|
+
- Acknowledgment system for guaranteed delivery
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def register_events(self):
|
|
28
|
+
"""Register enhanced connection event handlers."""
|
|
29
|
+
sio = self.server.core.sio
|
|
30
|
+
|
|
31
|
+
@sio.event
|
|
32
|
+
async def connect(sid, environ, auth):
|
|
33
|
+
"""Handle client connection with enhanced tracking."""
|
|
34
|
+
try:
|
|
35
|
+
# Extract client ID from auth or create new
|
|
36
|
+
client_id = None
|
|
37
|
+
if auth and isinstance(auth, dict):
|
|
38
|
+
client_id = auth.get("client_id")
|
|
39
|
+
|
|
40
|
+
# Register connection with manager
|
|
41
|
+
if self.server.connection_manager:
|
|
42
|
+
conn = await self.server.connection_manager.register_connection(
|
|
43
|
+
sid, client_id
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# Add to server's connected clients
|
|
47
|
+
self.server.connected_clients.add(sid)
|
|
48
|
+
self.server.stats["connections_total"] += 1
|
|
49
|
+
|
|
50
|
+
# Store client info
|
|
51
|
+
self.server.client_info[sid] = {
|
|
52
|
+
"client_id": conn.client_id,
|
|
53
|
+
"connected_at": datetime.now().isoformat(),
|
|
54
|
+
"user_agent": environ.get("HTTP_USER_AGENT", "unknown"),
|
|
55
|
+
"remote_addr": environ.get("REMOTE_ADDR", "unknown"),
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# Send client ID back for future reconnections
|
|
59
|
+
await sio.emit(
|
|
60
|
+
"connection_established",
|
|
61
|
+
{
|
|
62
|
+
"client_id": conn.client_id,
|
|
63
|
+
"sid": sid,
|
|
64
|
+
"timestamp": datetime.now().isoformat(),
|
|
65
|
+
"server_version": self.get_server_version(),
|
|
66
|
+
},
|
|
67
|
+
room=sid,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Send current server status
|
|
71
|
+
await self._send_server_status(sid)
|
|
72
|
+
|
|
73
|
+
# Check for events to replay
|
|
74
|
+
last_sequence = 0
|
|
75
|
+
if auth and isinstance(auth, dict):
|
|
76
|
+
last_sequence = auth.get("last_sequence", 0)
|
|
77
|
+
|
|
78
|
+
if last_sequence > 0:
|
|
79
|
+
replay_events = (
|
|
80
|
+
await self.server.connection_manager.get_replay_events(
|
|
81
|
+
sid, last_sequence
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if replay_events:
|
|
86
|
+
self.logger.info(
|
|
87
|
+
f"Replaying {len(replay_events)} events for client {conn.client_id}"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Send replay events in batch
|
|
91
|
+
await sio.emit(
|
|
92
|
+
"event_replay",
|
|
93
|
+
{
|
|
94
|
+
"events": replay_events,
|
|
95
|
+
"count": len(replay_events),
|
|
96
|
+
"from_sequence": last_sequence,
|
|
97
|
+
},
|
|
98
|
+
room=sid,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Send event history for initial population
|
|
102
|
+
if (
|
|
103
|
+
hasattr(self.server, "event_history")
|
|
104
|
+
and self.server.event_history
|
|
105
|
+
):
|
|
106
|
+
history_data = list(self.server.event_history)
|
|
107
|
+
await sio.emit(
|
|
108
|
+
"event_history",
|
|
109
|
+
{"events": history_data, "count": len(history_data)},
|
|
110
|
+
room=sid,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
self.logger.info(
|
|
114
|
+
f"Client connected: {conn.client_id} (sid: {sid}, "
|
|
115
|
+
f"reconnect: {conn.metrics.reconnect_count > 0})"
|
|
116
|
+
)
|
|
117
|
+
else:
|
|
118
|
+
# Fallback to basic connection tracking
|
|
119
|
+
self.server.connected_clients.add(sid)
|
|
120
|
+
self.server.stats["connections_total"] += 1
|
|
121
|
+
|
|
122
|
+
self.server.client_info[sid] = {
|
|
123
|
+
"connected_at": datetime.now().isoformat(),
|
|
124
|
+
"user_agent": environ.get("HTTP_USER_AGENT", "unknown"),
|
|
125
|
+
"remote_addr": environ.get("REMOTE_ADDR", "unknown"),
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
await self._send_server_status(sid)
|
|
129
|
+
|
|
130
|
+
if (
|
|
131
|
+
hasattr(self.server, "event_history")
|
|
132
|
+
and self.server.event_history
|
|
133
|
+
):
|
|
134
|
+
history_data = list(self.server.event_history)
|
|
135
|
+
await sio.emit(
|
|
136
|
+
"event_history",
|
|
137
|
+
{"events": history_data, "count": len(history_data)},
|
|
138
|
+
room=sid,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
self.logger.info(f"Client connected: {sid}")
|
|
142
|
+
|
|
143
|
+
except Exception as e:
|
|
144
|
+
self.logger.error(f"Error handling connection for {sid}: {e}")
|
|
145
|
+
|
|
146
|
+
@sio.event
|
|
147
|
+
async def disconnect(sid):
|
|
148
|
+
"""Handle client disconnection with state preservation."""
|
|
149
|
+
try:
|
|
150
|
+
# Get disconnection reason if available
|
|
151
|
+
reason = "client_disconnect"
|
|
152
|
+
|
|
153
|
+
# Unregister from connection manager but preserve state
|
|
154
|
+
if self.server.connection_manager:
|
|
155
|
+
await self.server.connection_manager.unregister_connection(
|
|
156
|
+
sid, reason
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# Remove from connected clients
|
|
160
|
+
if sid in self.server.connected_clients:
|
|
161
|
+
self.server.connected_clients.remove(sid)
|
|
162
|
+
|
|
163
|
+
# Remove client info
|
|
164
|
+
if sid in self.server.client_info:
|
|
165
|
+
client_info = self.server.client_info[sid]
|
|
166
|
+
del self.server.client_info[sid]
|
|
167
|
+
|
|
168
|
+
client_id = client_info.get("client_id", sid)
|
|
169
|
+
self.logger.info(f"Client disconnected: {client_id} (sid: {sid})")
|
|
170
|
+
else:
|
|
171
|
+
self.logger.info(f"Client disconnected: {sid}")
|
|
172
|
+
|
|
173
|
+
except Exception as e:
|
|
174
|
+
self.logger.error(f"Error handling disconnection for {sid}: {e}")
|
|
175
|
+
|
|
176
|
+
@sio.event
|
|
177
|
+
async def ping(sid):
|
|
178
|
+
"""Handle ping from client for health monitoring."""
|
|
179
|
+
try:
|
|
180
|
+
# Update activity in connection manager
|
|
181
|
+
if self.server.connection_manager:
|
|
182
|
+
await self.server.connection_manager.update_activity(sid, "ping")
|
|
183
|
+
|
|
184
|
+
# Send pong response with timestamp
|
|
185
|
+
await sio.emit(
|
|
186
|
+
"pong",
|
|
187
|
+
{
|
|
188
|
+
"timestamp": datetime.now().isoformat(),
|
|
189
|
+
"server_time": datetime.now().timestamp(),
|
|
190
|
+
},
|
|
191
|
+
room=sid,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
except Exception as e:
|
|
195
|
+
self.logger.error(f"Error handling ping from {sid}: {e}")
|
|
196
|
+
|
|
197
|
+
@sio.event
|
|
198
|
+
async def acknowledge_event(sid, data):
|
|
199
|
+
"""Handle event acknowledgment from client."""
|
|
200
|
+
try:
|
|
201
|
+
if not isinstance(data, dict):
|
|
202
|
+
return
|
|
203
|
+
|
|
204
|
+
sequence = data.get("sequence")
|
|
205
|
+
if sequence and self.server.connection_manager:
|
|
206
|
+
await self.server.connection_manager.acknowledge_event(
|
|
207
|
+
sid, sequence
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
# Optional: Send confirmation
|
|
211
|
+
await sio.emit(
|
|
212
|
+
"ack_confirmed",
|
|
213
|
+
{"sequence": sequence, "timestamp": datetime.now().isoformat()},
|
|
214
|
+
room=sid,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
except Exception as e:
|
|
218
|
+
self.logger.error(f"Error handling acknowledgment from {sid}: {e}")
|
|
219
|
+
|
|
220
|
+
@sio.event
|
|
221
|
+
async def request_replay(sid, data):
|
|
222
|
+
"""Handle replay request from client after reconnection."""
|
|
223
|
+
try:
|
|
224
|
+
if not isinstance(data, dict):
|
|
225
|
+
return
|
|
226
|
+
|
|
227
|
+
last_sequence = data.get("last_sequence", 0)
|
|
228
|
+
|
|
229
|
+
if self.server.connection_manager:
|
|
230
|
+
replay_events = (
|
|
231
|
+
await self.server.connection_manager.get_replay_events(
|
|
232
|
+
sid, last_sequence
|
|
233
|
+
)
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
if replay_events:
|
|
237
|
+
await sio.emit(
|
|
238
|
+
"event_replay",
|
|
239
|
+
{
|
|
240
|
+
"events": replay_events,
|
|
241
|
+
"count": len(replay_events),
|
|
242
|
+
"from_sequence": last_sequence,
|
|
243
|
+
},
|
|
244
|
+
room=sid,
|
|
245
|
+
)
|
|
246
|
+
else:
|
|
247
|
+
await sio.emit(
|
|
248
|
+
"event_replay",
|
|
249
|
+
{
|
|
250
|
+
"events": [],
|
|
251
|
+
"count": 0,
|
|
252
|
+
"from_sequence": last_sequence,
|
|
253
|
+
"message": "No events to replay",
|
|
254
|
+
},
|
|
255
|
+
room=sid,
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
except Exception as e:
|
|
259
|
+
self.logger.error(f"Error handling replay request from {sid}: {e}")
|
|
260
|
+
|
|
261
|
+
@sio.event
|
|
262
|
+
async def get_connection_stats(sid):
|
|
263
|
+
"""Get connection statistics for debugging."""
|
|
264
|
+
try:
|
|
265
|
+
stats = {
|
|
266
|
+
"timestamp": datetime.now().isoformat(),
|
|
267
|
+
"total_connections": len(self.server.connected_clients),
|
|
268
|
+
"server_stats": self.server.stats,
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if self.server.connection_manager:
|
|
272
|
+
conn = self.server.connection_manager.get_connection(sid)
|
|
273
|
+
if conn:
|
|
274
|
+
stats["connection"] = {
|
|
275
|
+
"client_id": conn.client_id,
|
|
276
|
+
"state": conn.state.value,
|
|
277
|
+
"connected_at": conn.connected_at,
|
|
278
|
+
"quality": conn.calculate_quality(),
|
|
279
|
+
"metrics": {
|
|
280
|
+
"events_sent": conn.metrics.events_sent,
|
|
281
|
+
"events_acked": conn.metrics.events_acked,
|
|
282
|
+
"events_buffered": conn.metrics.events_buffered,
|
|
283
|
+
"reconnect_count": conn.metrics.reconnect_count,
|
|
284
|
+
},
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
stats["manager_metrics"] = (
|
|
288
|
+
self.server.connection_manager.get_metrics()
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
await sio.emit("connection_stats", stats, room=sid)
|
|
292
|
+
|
|
293
|
+
except Exception as e:
|
|
294
|
+
self.logger.error(f"Error getting connection stats for {sid}: {e}")
|
|
295
|
+
|
|
296
|
+
@sio.event
|
|
297
|
+
async def heartbeat(sid):
|
|
298
|
+
"""Handle client heartbeat for connection monitoring."""
|
|
299
|
+
try:
|
|
300
|
+
# Update activity
|
|
301
|
+
if self.server.connection_manager:
|
|
302
|
+
await self.server.connection_manager.update_activity(sid, "event")
|
|
303
|
+
|
|
304
|
+
# Send heartbeat response
|
|
305
|
+
await sio.emit(
|
|
306
|
+
"heartbeat_response",
|
|
307
|
+
{"timestamp": datetime.now().isoformat(), "status": "alive"},
|
|
308
|
+
room=sid,
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
except Exception as e:
|
|
312
|
+
self.logger.error(f"Error handling heartbeat from {sid}: {e}")
|
|
313
|
+
|
|
314
|
+
self.logger.info("Enhanced connection event handlers registered")
|
|
315
|
+
|
|
316
|
+
async def _send_server_status(self, sid: str):
|
|
317
|
+
"""Send current server status to a client."""
|
|
318
|
+
try:
|
|
319
|
+
status_data = {
|
|
320
|
+
"server_running": self.server.running,
|
|
321
|
+
"claude_status": self.server.claude_status,
|
|
322
|
+
"claude_pid": self.server.claude_pid,
|
|
323
|
+
"session_id": self.server.session_id,
|
|
324
|
+
"connected_clients": len(self.server.connected_clients),
|
|
325
|
+
"server_start_time": (
|
|
326
|
+
self.server.stats.get("start_time").isoformat()
|
|
327
|
+
if self.server.stats.get("start_time")
|
|
328
|
+
else None
|
|
329
|
+
),
|
|
330
|
+
"timestamp": datetime.now().isoformat(),
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
await self.server.core.sio.emit("server_status", status_data, room=sid)
|
|
334
|
+
|
|
335
|
+
except Exception as e:
|
|
336
|
+
self.logger.error(f"Error sending server status to {sid}: {e}")
|
|
337
|
+
|
|
338
|
+
def get_server_version(self) -> str:
|
|
339
|
+
"""Get server version for client info."""
|
|
340
|
+
try:
|
|
341
|
+
from claude_mpm.services.version_service import VersionService
|
|
342
|
+
|
|
343
|
+
return VersionService().get_version()
|
|
344
|
+
except:
|
|
345
|
+
return "unknown"
|
|
@@ -153,6 +153,7 @@ class SocketIOEventBroadcaster:
|
|
|
153
153
|
stats: Dict[str, Any],
|
|
154
154
|
logger,
|
|
155
155
|
server=None, # Add server reference for event history access
|
|
156
|
+
connection_manager=None, # Add connection manager for robust delivery
|
|
156
157
|
):
|
|
157
158
|
self.sio = sio
|
|
158
159
|
self.connected_clients = connected_clients
|
|
@@ -162,6 +163,7 @@ class SocketIOEventBroadcaster:
|
|
|
162
163
|
self.logger = logger
|
|
163
164
|
self.loop = None # Will be set by main server
|
|
164
165
|
self.server = server # Reference to main server for event history
|
|
166
|
+
self.connection_manager = connection_manager # For connection tracking
|
|
165
167
|
|
|
166
168
|
# Initialize retry queue for resilient delivery
|
|
167
169
|
self.retry_queue = RetryQueue(max_size=1000)
|
|
@@ -313,7 +315,7 @@ class SocketIOEventBroadcaster:
|
|
|
313
315
|
|
|
314
316
|
WHY: Enhanced with retry queue to ensure reliable delivery
|
|
315
317
|
even during transient network issues. Now uses EventNormalizer
|
|
316
|
-
to ensure consistent event schema.
|
|
318
|
+
to ensure consistent event schema and ConnectionManager for tracking.
|
|
317
319
|
"""
|
|
318
320
|
if not self.sio:
|
|
319
321
|
return
|
|
@@ -342,6 +344,18 @@ class SocketIOEventBroadcaster:
|
|
|
342
344
|
f"Added {event['type']}/{event['subtype']} to history (total: {len(self.server.event_history)})"
|
|
343
345
|
)
|
|
344
346
|
|
|
347
|
+
# If we have a connection manager, buffer event for all connected clients
|
|
348
|
+
if self.connection_manager and self.loop:
|
|
349
|
+
# Buffer for each connected client asynchronously
|
|
350
|
+
async def buffer_for_clients():
|
|
351
|
+
for sid in list(self.connected_clients):
|
|
352
|
+
await self.connection_manager.buffer_event(sid, event)
|
|
353
|
+
|
|
354
|
+
try:
|
|
355
|
+
asyncio.run_coroutine_threadsafe(buffer_for_clients(), self.loop)
|
|
356
|
+
except Exception as e:
|
|
357
|
+
self.logger.warning(f"Failed to buffer event for clients: {e}")
|
|
358
|
+
|
|
345
359
|
# Broadcast to all connected clients
|
|
346
360
|
broadcast_success = False
|
|
347
361
|
try:
|
|
@@ -360,6 +374,23 @@ class SocketIOEventBroadcaster:
|
|
|
360
374
|
future.result(timeout=0.5) # 500ms timeout
|
|
361
375
|
broadcast_success = True
|
|
362
376
|
self.stats["events_sent"] += 1
|
|
377
|
+
|
|
378
|
+
# Update activity for all connected clients
|
|
379
|
+
if self.connection_manager:
|
|
380
|
+
|
|
381
|
+
async def update_activities():
|
|
382
|
+
for sid in list(self.connected_clients):
|
|
383
|
+
await self.connection_manager.update_activity(
|
|
384
|
+
sid, "event"
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
try:
|
|
388
|
+
asyncio.run_coroutine_threadsafe(
|
|
389
|
+
update_activities(), self.loop
|
|
390
|
+
)
|
|
391
|
+
except:
|
|
392
|
+
pass # Non-critical
|
|
393
|
+
|
|
363
394
|
self.logger.debug(f"Broadcasted event: {event_type}")
|
|
364
395
|
except:
|
|
365
396
|
# Will be added to retry queue below
|