MCPcopy Create free account
hub / github.com/bigdra50/unity-cli / _heartbeat_loop

Method _heartbeat_loop

relay/server.py:342–409  ·  view source on GitHub ↗

Send periodic heartbeats to Unity instance. Implements: - Single Outstanding PING: Wait for PONG before sending next PING - 3 consecutive failures → DISCONNECTED - Extended timeout during RELOADING state

(self, instance_id: str)

Source from the content-addressed store, hash-verified

340 logger.warning(f"Unknown Unity message type: {msg_type}")
341
342 async def _heartbeat_loop(self, instance_id: str) -> None:
343 """
344 Send periodic heartbeats to Unity instance.
345
346 Implements:
347 - Single Outstanding PING: Wait for PONG before sending next PING
348 - 3 consecutive failures → DISCONNECTED
349 - Extended timeout during RELOADING state
350 """
351 consecutive_failures = 0
352
353 try:
354 while self._running:
355 # Wait before sending next PING
356 await asyncio.sleep(HEARTBEAT_INTERVAL_MS / 1000)
357
358 instance = self.registry.get(instance_id)
359 if not instance or not instance.is_connected:
360 break
361
362 # Determine timeout based on instance state
363 if instance.status == InstanceStatus.RELOADING:
364 timeout_ms = RELOAD_TIMEOUT_MS
365 else:
366 timeout_ms = HEARTBEAT_TIMEOUT_MS
367
368 # Create event for PONG response (Single Outstanding PING)
369 pong_event = asyncio.Event()
370 self._pending_pongs[instance_id] = pong_event
371
372 try:
373 # Send PING
374 ping = PingMessage()
375 await write_frame(instance.writer, ping.to_dict())
376 logger.debug(f"PING sent to {instance_id}")
377
378 # Wait for PONG with timeout
379 try:
380 await asyncio.wait_for(pong_event.wait(), timeout=timeout_ms / 1000)
381 # PONG received - reset failure counter
382 consecutive_failures = 0
383 logger.debug(f"Heartbeat OK for {instance_id}")
384
385 except TimeoutError:
386 consecutive_failures += 1
387 logger.warning(
388 f"Heartbeat timeout for {instance_id} ({consecutive_failures}/{HEARTBEAT_MAX_RETRIES})"
389 )
390
391 if consecutive_failures >= HEARTBEAT_MAX_RETRIES:
392 logger.error(f"Heartbeat failed {HEARTBEAT_MAX_RETRIES} times, disconnecting {instance_id}")
393 break
394
395 except Exception as e:
396 logger.warning(f"Failed to send heartbeat to {instance_id}: {e}")
397 consecutive_failures += 1
398 if consecutive_failures >= HEARTBEAT_MAX_RETRIES:
399 break

Callers 1

Calls 4

PingMessageClass · 0.85
write_frameFunction · 0.85
getMethod · 0.45
to_dictMethod · 0.45

Tested by

no test coverage detected